mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-09-07 09:05:57 -05:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
21a00d47cc |
5
.github/scripts/.Aptfile
vendored
5
.github/scripts/.Aptfile
vendored
@@ -7,8 +7,3 @@ package 'ninja-build', bin: 'ninja'
|
|||||||
package 'pkg-config'
|
package 'pkg-config'
|
||||||
package 'clang'
|
package 'clang'
|
||||||
package 'clang-format-13'
|
package 'clang-format-13'
|
||||||
package 'libxtst-dev'
|
|
||||||
package 'libxss-dev'
|
|
||||||
package 'libopencv-dev'
|
|
||||||
package 'libtesseract-dev'
|
|
||||||
package 'libprocps-dev'
|
|
||||||
|
|||||||
7
.github/scripts/utils.zsh/setup_linux
vendored
7
.github/scripts/utils.zsh/setup_linux
vendored
@@ -34,6 +34,13 @@ if (( ! (${skips[(Ie)all]} + ${skips[(Ie)deps]}) )) {
|
|||||||
|
|
||||||
log_info 'Installing obs plugin dependencies...'
|
log_info 'Installing obs plugin dependencies...'
|
||||||
|
|
||||||
|
sudo apt-get install -y \
|
||||||
|
libxtst-dev \
|
||||||
|
libxss-dev \
|
||||||
|
libopencv-dev \
|
||||||
|
libtesseract-dev \
|
||||||
|
libprocps-dev
|
||||||
|
|
||||||
local -a _qt_packages=()
|
local -a _qt_packages=()
|
||||||
|
|
||||||
if (( QT_VERSION == 5 )) {
|
if (( QT_VERSION == 5 )) {
|
||||||
|
|||||||
@@ -93,12 +93,8 @@ target_sources(
|
|||||||
${LIB_NAME}
|
${LIB_NAME}
|
||||||
PRIVATE src/macro-core/macro-action-audio.cpp
|
PRIVATE src/macro-core/macro-action-audio.cpp
|
||||||
src/macro-core/macro-action-audio.hpp
|
src/macro-core/macro-action-audio.hpp
|
||||||
src/macro-core/macro-action-clipboard.cpp
|
|
||||||
src/macro-core/macro-action-clipboard.hpp
|
|
||||||
src/macro-core/macro-action-edit.cpp
|
src/macro-core/macro-action-edit.cpp
|
||||||
src/macro-core/macro-action-edit.hpp
|
src/macro-core/macro-action-edit.hpp
|
||||||
src/macro-core/macro-action-factory.cpp
|
|
||||||
src/macro-core/macro-action-factory.hpp
|
|
||||||
src/macro-core/macro-action-file.cpp
|
src/macro-core/macro-action-file.cpp
|
||||||
src/macro-core/macro-action-file.hpp
|
src/macro-core/macro-action-file.hpp
|
||||||
src/macro-core/macro-action-filter.cpp
|
src/macro-core/macro-action-filter.cpp
|
||||||
@@ -175,8 +171,6 @@ target_sources(
|
|||||||
src/macro-core/macro-condition-display.hpp
|
src/macro-core/macro-condition-display.hpp
|
||||||
src/macro-core/macro-condition-edit.cpp
|
src/macro-core/macro-condition-edit.cpp
|
||||||
src/macro-core/macro-condition-edit.hpp
|
src/macro-core/macro-condition-edit.hpp
|
||||||
src/macro-core/macro-condition-factory.cpp
|
|
||||||
src/macro-core/macro-condition-factory.hpp
|
|
||||||
src/macro-core/macro-condition-file.cpp
|
src/macro-core/macro-condition-file.cpp
|
||||||
src/macro-core/macro-condition-file.hpp
|
src/macro-core/macro-condition-file.hpp
|
||||||
src/macro-core/macro-condition-filter.cpp
|
src/macro-core/macro-condition-filter.cpp
|
||||||
@@ -237,8 +231,6 @@ target_sources(
|
|||||||
src/macro-core/macro-condition.hpp
|
src/macro-core/macro-condition.hpp
|
||||||
src/macro-core/macro-dock.cpp
|
src/macro-core/macro-dock.cpp
|
||||||
src/macro-core/macro-dock.hpp
|
src/macro-core/macro-dock.hpp
|
||||||
src/macro-core/macro-helpers.cpp
|
|
||||||
src/macro-core/macro-helpers.hpp
|
|
||||||
src/macro-core/macro-properties.cpp
|
src/macro-core/macro-properties.cpp
|
||||||
src/macro-core/macro-properties.hpp
|
src/macro-core/macro-properties.hpp
|
||||||
src/macro-core/macro-ref.cpp
|
src/macro-core/macro-ref.cpp
|
||||||
@@ -262,8 +254,6 @@ target_sources(
|
|||||||
src/utils/connection-manager.hpp
|
src/utils/connection-manager.hpp
|
||||||
src/utils/curl-helper.cpp
|
src/utils/curl-helper.cpp
|
||||||
src/utils/curl-helper.hpp
|
src/utils/curl-helper.hpp
|
||||||
src/utils/duration.cpp
|
|
||||||
src/utils/duration.hpp
|
|
||||||
src/utils/duration-control.cpp
|
src/utils/duration-control.cpp
|
||||||
src/utils/duration-control.hpp
|
src/utils/duration-control.hpp
|
||||||
src/utils/export-symbol-helper.hpp
|
src/utils/export-symbol-helper.hpp
|
||||||
@@ -297,8 +287,6 @@ target_sources(
|
|||||||
src/utils/obs-module-helper.hpp
|
src/utils/obs-module-helper.hpp
|
||||||
src/utils/osc-helpers.cpp
|
src/utils/osc-helpers.cpp
|
||||||
src/utils/osc-helpers.hpp
|
src/utils/osc-helpers.hpp
|
||||||
src/utils/plugin-state-helpers.cpp
|
|
||||||
src/utils/plugin-state-helpers.hpp
|
|
||||||
src/utils/priority-helper.cpp
|
src/utils/priority-helper.cpp
|
||||||
src/utils/priority-helper.hpp
|
src/utils/priority-helper.hpp
|
||||||
src/utils/process-config.cpp
|
src/utils/process-config.cpp
|
||||||
@@ -329,8 +317,8 @@ target_sources(
|
|||||||
src/utils/striped-frame.hpp
|
src/utils/striped-frame.hpp
|
||||||
src/utils/switch-button.cpp
|
src/utils/switch-button.cpp
|
||||||
src/utils/switch-button.hpp
|
src/utils/switch-button.hpp
|
||||||
src/utils/sync-helpers.cpp
|
src/utils/sync-helper.cpp
|
||||||
src/utils/sync-helpers.hpp
|
src/utils/sync-helper.hpp
|
||||||
src/utils/temp-variable.cpp
|
src/utils/temp-variable.cpp
|
||||||
src/utils/temp-variable.hpp
|
src/utils/temp-variable.hpp
|
||||||
src/utils/transition-selection.cpp
|
src/utils/transition-selection.cpp
|
||||||
@@ -470,24 +458,27 @@ else()
|
|||||||
|
|
||||||
find_path(PROCPS_INCLUDE_DIR NAMES proc/procps.h)
|
find_path(PROCPS_INCLUDE_DIR NAMES proc/procps.h)
|
||||||
find_path(PROCPS2_INCLUDE_DIR NAMES libproc2/pids.h)
|
find_path(PROCPS2_INCLUDE_DIR NAMES libproc2/pids.h)
|
||||||
if(PROCPS_INCLUDE_DIR)
|
find_library(PROCPS_LIBRARY NAMES procps)
|
||||||
|
find_library(PROCPS2_LIBRARY NAMES proc2)
|
||||||
|
if(PROCPS_INCLUDE_DIR AND PROCPS_LIBRARY)
|
||||||
message(STATUS "${PROJECT_NAME} using procps")
|
message(STATUS "${PROJECT_NAME} using procps")
|
||||||
set(PROC_INCLUDE_DIR "${PROCPS_INCLUDE_DIR}")
|
set(PROC_INCLUDE_DIR "${PROCPS_INCLUDE_DIR}")
|
||||||
target_compile_definitions(${LIB_NAME} PRIVATE PROCPS_AVAILABLE)
|
set(PROC_LIBRARY "${PROCPS_LIBRARY}")
|
||||||
set(PROCESS_CONDITION_SUPPORTED 1)
|
target_compile_definitions(${LIB_NAME} PRIVATE USE_PROCPS)
|
||||||
endif()
|
elseif(PROCPS2_INCLUDE_DIR AND PROCPS2_LIBRARY)
|
||||||
if(PROCPS2_INCLUDE_DIR)
|
|
||||||
message(STATUS "${PROJECT_NAME} using libproc2")
|
message(STATUS "${PROJECT_NAME} using libproc2")
|
||||||
set(PROC_INCLUDE_DIR "${PROCPS2_INCLUDE_DIR}")
|
set(PROC_INCLUDE_DIR "${PROCPS2_INCLUDE_DIR}")
|
||||||
target_compile_definitions(${LIB_NAME} PRIVATE PROCPS2_AVAILABLE)
|
set(PROC_LIBRARY "${PROCPS2_LIBRARY}")
|
||||||
set(PROCESS_CONDITION_SUPPORTED 1)
|
else()
|
||||||
endif()
|
|
||||||
if(NOT DEFINED PROCESS_CONDITION_SUPPORTED)
|
|
||||||
message(
|
message(
|
||||||
WARNING
|
FATAL_ERROR
|
||||||
"found neither procps nor libproc2! Process condition will not be functional!"
|
"found neither procps nor libproc2!
|
||||||
)
|
please either set ...
|
||||||
|
PROCPS_INCLUDE_DIR and PROCPS_LIBRARY
|
||||||
|
... or ...
|
||||||
|
PROCPS2_INCLUDE_DIR and PROCPS2_LIBRARY")
|
||||||
endif()
|
endif()
|
||||||
|
target_link_libraries(${LIB_NAME} PRIVATE "${PROC_LIBRARY}")
|
||||||
target_include_directories(${LIB_NAME} PRIVATE "${PROC_INCLUDE_DIR}")
|
target_include_directories(${LIB_NAME} PRIVATE "${PROC_INCLUDE_DIR}")
|
||||||
|
|
||||||
find_package(CURL)
|
find_package(CURL)
|
||||||
|
|||||||
@@ -159,6 +159,7 @@ 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"
|
||||||
AdvSceneSwitcher.condition.media.allOnScene="Alle Medienquellen in"
|
AdvSceneSwitcher.condition.media.allOnScene="Alle Medienquellen in"
|
||||||
|
AdvSceneSwitcher.condition.media.matchOnChange="Nur bei Änderung übereinstimmen (Hinweis: Diese Option wird in einer zukünftigen Version entfernt werden - bitte stattdessen Dauer-Modifikatoren verwenden)"
|
||||||
AdvSceneSwitcher.condition.media.inconsistencyInfo="Leider verhalten sich nicht alle Medien-Quell-Typen gleich (z.B. Medien-Quelle vs. VLC-Video-Quelle \"Gestoppt\"-Status).\nBitte experimentieren, was in eurem Setup funktioniert!"
|
AdvSceneSwitcher.condition.media.inconsistencyInfo="Leider verhalten sich nicht alle Medien-Quell-Typen gleich (z.B. Medien-Quelle vs. VLC-Video-Quelle \"Gestoppt\"-Status).\nBitte experimentieren, was in eurem Setup funktioniert!"
|
||||||
AdvSceneSwitcher.condition.media.entry="{{sourceTypes}}{{mediaSources}}{{scenes}}Status ist{{states}}und{{timeRestrictions}}{{time}}"
|
AdvSceneSwitcher.condition.media.entry="{{sourceTypes}}{{mediaSources}}{{scenes}}Status ist{{states}}und{{timeRestrictions}}{{time}}"
|
||||||
AdvSceneSwitcher.condition.video="Video"
|
AdvSceneSwitcher.condition.video="Video"
|
||||||
@@ -220,8 +221,9 @@ AdvSceneSwitcher.condition.record="Aufnahme"
|
|||||||
AdvSceneSwitcher.condition.record.state.start="Aufnahme läuft"
|
AdvSceneSwitcher.condition.record.state.start="Aufnahme läuft"
|
||||||
AdvSceneSwitcher.condition.record.state.pause="Aufnahme pausiert"
|
AdvSceneSwitcher.condition.record.state.pause="Aufnahme pausiert"
|
||||||
AdvSceneSwitcher.condition.record.state.stop="Aufnahme gestoppt"
|
AdvSceneSwitcher.condition.record.state.stop="Aufnahme gestoppt"
|
||||||
|
AdvSceneSwitcher.condition.record.entry="{{recordState}}"
|
||||||
AdvSceneSwitcher.condition.process="Prozess"
|
AdvSceneSwitcher.condition.process="Prozess"
|
||||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}läuft{{focused}}und ist fokusiert"
|
AdvSceneSwitcher.condition.process.entry="{{processes}} läuft {{focused}} und ist fokusiert"
|
||||||
AdvSceneSwitcher.condition.process.entry.focus="Aktueller Vordergrundprozess: {{focusProcess}}"
|
AdvSceneSwitcher.condition.process.entry.focus="Aktueller Vordergrundprozess: {{focusProcess}}"
|
||||||
AdvSceneSwitcher.condition.idle="Leerlauf"
|
AdvSceneSwitcher.condition.idle="Leerlauf"
|
||||||
AdvSceneSwitcher.condition.idle.entry="Keine Tastatur- oder Mauseingaben für {{duration}}"
|
AdvSceneSwitcher.condition.idle.entry="Keine Tastatur- oder Mauseingaben für {{duration}}"
|
||||||
@@ -573,6 +575,7 @@ AdvSceneSwitcher.action.variable.invalidSelection="Ungültige Auswahl!"
|
|||||||
AdvSceneSwitcher.action.variable.actionNoVariableSupport="Das Abrufen von Variablenwerten aus %1 Aktionen wird nicht unterstützt!"
|
AdvSceneSwitcher.action.variable.actionNoVariableSupport="Das Abrufen von Variablenwerten aus %1 Aktionen wird nicht unterstützt!"
|
||||||
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="Das Abrufen von Variablenwerten aus %1 Bedingungen wird nicht unterstützt!"
|
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="Das Abrufen von Variablenwerten aus %1 Bedingungen wird nicht unterstützt!"
|
||||||
AdvSceneSwitcher.action.variable.currentSegmentValue="Aktueller Wert:"
|
AdvSceneSwitcher.action.variable.currentSegmentValue="Aktueller Wert:"
|
||||||
|
AdvSceneSwitcher.action.variable.entry="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}{{envVariableName}}{{scenes}}{{tempVars}}"
|
||||||
|
|
||||||
|
|
||||||
; Transition Tab
|
; Transition Tab
|
||||||
|
|||||||
@@ -79,7 +79,6 @@ AdvSceneSwitcher.macroTab.edit.action="Action type:"
|
|||||||
AdvSceneSwitcher.macroTab.add="Add new macro"
|
AdvSceneSwitcher.macroTab.add="Add new macro"
|
||||||
AdvSceneSwitcher.macroTab.name="Name:"
|
AdvSceneSwitcher.macroTab.name="Name:"
|
||||||
AdvSceneSwitcher.macroTab.run="Run macro"
|
AdvSceneSwitcher.macroTab.run="Run macro"
|
||||||
AdvSceneSwitcher.macroTab.run.tooltip="Run all macro actions regardless of condition.\nIf else actions are available, hold Shift and click the button to execute them instead."
|
|
||||||
AdvSceneSwitcher.macroTab.runElse="Run macro (else)"
|
AdvSceneSwitcher.macroTab.runElse="Run macro (else)"
|
||||||
AdvSceneSwitcher.macroTab.runFail="Running \"%1\" failed!\nEither one of the actions failed or the macro is running already."
|
AdvSceneSwitcher.macroTab.runFail="Running \"%1\" failed!\nEither one of the actions failed or the macro is running already."
|
||||||
AdvSceneSwitcher.macroTab.runInParallel="Run macro in parallel to other macros"
|
AdvSceneSwitcher.macroTab.runInParallel="Run macro in parallel to other macros"
|
||||||
@@ -126,8 +125,6 @@ AdvSceneSwitcher.macroTab.currentDockButtonText.unpause="Unpause button text:"
|
|||||||
AdvSceneSwitcher.macroTab.currentDockStatusText.true="Conditions true text:"
|
AdvSceneSwitcher.macroTab.currentDockStatusText.true="Conditions true text:"
|
||||||
AdvSceneSwitcher.macroTab.currentDockStatusText.false="Conditions false text:"
|
AdvSceneSwitcher.macroTab.currentDockStatusText.false="Conditions false text:"
|
||||||
AdvSceneSwitcher.macroTab.currentDockHighlightIfExecuted="Highlight dock if macro actions were recently executed"
|
AdvSceneSwitcher.macroTab.currentDockHighlightIfExecuted="Highlight dock if macro actions were recently executed"
|
||||||
AdvSceneSwitcher.macroTab.toggleElseActions.hide.tooltip="Hide else actions"
|
|
||||||
AdvSceneSwitcher.macroTab.toggleElseActions.show.tooltip="Show else actions"
|
|
||||||
|
|
||||||
AdvSceneSwitcher.macroDock.pause="Pause"
|
AdvSceneSwitcher.macroDock.pause="Pause"
|
||||||
AdvSceneSwitcher.macroDock.unpause="Unpause"
|
AdvSceneSwitcher.macroDock.unpause="Unpause"
|
||||||
@@ -207,6 +204,7 @@ 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"
|
||||||
AdvSceneSwitcher.condition.media.allOnScene="All media sources on"
|
AdvSceneSwitcher.condition.media.allOnScene="All media sources on"
|
||||||
|
AdvSceneSwitcher.condition.media.matchOnChange="Only match on change (Note: This option will be removed in a future version - please use duration modifiers instead)"
|
||||||
AdvSceneSwitcher.condition.media.inconsistencyInfo="Unfortunately not all media source types behave the same (e.g. Media Source vs. VLC Video Source \"Stopped\" state).\nSo please experiment what works for your setup!"
|
AdvSceneSwitcher.condition.media.inconsistencyInfo="Unfortunately not all media source types behave the same (e.g. Media Source vs. VLC Video Source \"Stopped\" state).\nSo please experiment what works for your setup!"
|
||||||
AdvSceneSwitcher.condition.media.entry="{{sourceTypes}}{{mediaSources}}{{scenes}}state is{{states}}and{{timeRestrictions}}{{time}}"
|
AdvSceneSwitcher.condition.media.entry="{{sourceTypes}}{{mediaSources}}{{scenes}}state is{{states}}and{{timeRestrictions}}{{time}}"
|
||||||
AdvSceneSwitcher.condition.video="Video"
|
AdvSceneSwitcher.condition.video="Video"
|
||||||
@@ -297,10 +295,10 @@ AdvSceneSwitcher.condition.record="Recording"
|
|||||||
AdvSceneSwitcher.condition.record.state.start="Recording running"
|
AdvSceneSwitcher.condition.record.state.start="Recording running"
|
||||||
AdvSceneSwitcher.condition.record.state.pause="Recording paused"
|
AdvSceneSwitcher.condition.record.state.pause="Recording paused"
|
||||||
AdvSceneSwitcher.condition.record.state.stop="Recording stopped"
|
AdvSceneSwitcher.condition.record.state.stop="Recording stopped"
|
||||||
AdvSceneSwitcher.condition.record.state.duration="Recording duration is longer than"
|
AdvSceneSwitcher.condition.record.state.saveDone="Recording saved"
|
||||||
AdvSceneSwitcher.condition.record.entry="{{condition}}{{duration}}"
|
AdvSceneSwitcher.condition.record.entry="{{recordState}}"
|
||||||
AdvSceneSwitcher.condition.process="Process"
|
AdvSceneSwitcher.condition.process="Process"
|
||||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}is running{{focused}}and is focused"
|
AdvSceneSwitcher.condition.process.entry="{{processes}}is running{{focused}}and is focused"
|
||||||
AdvSceneSwitcher.condition.process.entry.focus="Current foreground process:{{focusProcess}}"
|
AdvSceneSwitcher.condition.process.entry.focus="Current foreground process:{{focusProcess}}"
|
||||||
AdvSceneSwitcher.condition.idle="Idle"
|
AdvSceneSwitcher.condition.idle="Idle"
|
||||||
AdvSceneSwitcher.condition.idle.entry="No keyboard or mouse inputs for{{duration}}"
|
AdvSceneSwitcher.condition.idle.entry="No keyboard or mouse inputs for{{duration}}"
|
||||||
@@ -329,7 +327,6 @@ AdvSceneSwitcher.condition.macro.type.state="Macro condition state"
|
|||||||
AdvSceneSwitcher.condition.macro.type.multiState="Multiple macro condition state"
|
AdvSceneSwitcher.condition.macro.type.multiState="Multiple macro condition state"
|
||||||
AdvSceneSwitcher.condition.macro.type.actionDisabled="Macro action disabled"
|
AdvSceneSwitcher.condition.macro.type.actionDisabled="Macro action disabled"
|
||||||
AdvSceneSwitcher.condition.macro.type.actionEnabled="Macro action enabled"
|
AdvSceneSwitcher.condition.macro.type.actionEnabled="Macro action enabled"
|
||||||
AdvSceneSwitcher.condition.macro.type.paused="Macro is paused"
|
|
||||||
AdvSceneSwitcher.condition.macro.type.selection="{{types}}"
|
AdvSceneSwitcher.condition.macro.type.selection="{{types}}"
|
||||||
AdvSceneSwitcher.condition.macro.count.type.below="Less than"
|
AdvSceneSwitcher.condition.macro.count.type.below="Less than"
|
||||||
AdvSceneSwitcher.condition.macro.count.type.above="More than"
|
AdvSceneSwitcher.condition.macro.count.type.above="More than"
|
||||||
@@ -345,7 +342,6 @@ AdvSceneSwitcher.condition.macro.count.entry.line1="{{macros}}was executed{{cond
|
|||||||
AdvSceneSwitcher.condition.macro.count.entry.line2="Current count:{{currentCount}}{{resetCount}}"
|
AdvSceneSwitcher.condition.macro.count.entry.line2="Current count:{{currentCount}}{{resetCount}}"
|
||||||
AdvSceneSwitcher.condition.macro.actionState.disabled.entry="Action{{actionIndex}}of{{macros}}is disabled"
|
AdvSceneSwitcher.condition.macro.actionState.disabled.entry="Action{{actionIndex}}of{{macros}}is disabled"
|
||||||
AdvSceneSwitcher.condition.macro.actionState.enabled.entry="Action{{actionIndex}}of{{macros}}is enabled"
|
AdvSceneSwitcher.condition.macro.actionState.enabled.entry="Action{{actionIndex}}of{{macros}}is enabled"
|
||||||
AdvSceneSwitcher.condition.macro.paused.entry="Macro{{macros}}is paused"
|
|
||||||
AdvSceneSwitcher.condition.source="Source"
|
AdvSceneSwitcher.condition.source="Source"
|
||||||
AdvSceneSwitcher.condition.source.type.active="Is active"
|
AdvSceneSwitcher.condition.source.type.active="Is active"
|
||||||
AdvSceneSwitcher.condition.source.type.showing="Is showing"
|
AdvSceneSwitcher.condition.source.type.showing="Is showing"
|
||||||
@@ -609,7 +605,6 @@ AdvSceneSwitcher.action.streaming.type.username="Set username"
|
|||||||
AdvSceneSwitcher.action.streaming.type.password="Set password"
|
AdvSceneSwitcher.action.streaming.type.password="Set password"
|
||||||
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
|
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
|
||||||
AdvSceneSwitcher.action.run="Run"
|
AdvSceneSwitcher.action.run="Run"
|
||||||
AdvSceneSwitcher.action.run.entry.wait="{{wait}}Wait for process exit or at most {{timeout}}"
|
|
||||||
AdvSceneSwitcher.action.sceneVisibility="Scene item visibility"
|
AdvSceneSwitcher.action.sceneVisibility="Scene item visibility"
|
||||||
AdvSceneSwitcher.action.sceneVisibility.type.show="Show"
|
AdvSceneSwitcher.action.sceneVisibility.type.show="Show"
|
||||||
AdvSceneSwitcher.action.sceneVisibility.type.hide="Hide"
|
AdvSceneSwitcher.action.sceneVisibility.type.hide="Hide"
|
||||||
@@ -820,7 +815,6 @@ AdvSceneSwitcher.action.variable.type.sceneItemCount="Set to scene item count of
|
|||||||
AdvSceneSwitcher.action.variable.type.stringLength="Set to length of string"
|
AdvSceneSwitcher.action.variable.type.stringLength="Set to length of string"
|
||||||
AdvSceneSwitcher.action.variable.type.extractJson="Extract json field with name"
|
AdvSceneSwitcher.action.variable.type.extractJson="Extract json field with name"
|
||||||
AdvSceneSwitcher.action.variable.type.setToTempvar="Set to macro property"
|
AdvSceneSwitcher.action.variable.type.setToTempvar="Set to macro property"
|
||||||
AdvSceneSwitcher.action.variable.type.sceneItemName="Set to scene item name at index"
|
|
||||||
AdvSceneSwitcher.action.variable.askForValuePromptDefault="Assign value to variable \"%1\":"
|
AdvSceneSwitcher.action.variable.askForValuePromptDefault="Assign value to variable \"%1\":"
|
||||||
AdvSceneSwitcher.action.variable.askForValuePrompt="Assign value to variable:"
|
AdvSceneSwitcher.action.variable.askForValuePrompt="Assign value to variable:"
|
||||||
AdvSceneSwitcher.action.variable.mathExpression.example="( 1 + 2 * 3 ) / 4"
|
AdvSceneSwitcher.action.variable.mathExpression.example="( 1 + 2 * 3 ) / 4"
|
||||||
@@ -832,7 +826,7 @@ AdvSceneSwitcher.action.variable.invalidSelection="Invalid selection!"
|
|||||||
AdvSceneSwitcher.action.variable.actionNoVariableSupport="Getting variable values from %1 actions is not supported!"
|
AdvSceneSwitcher.action.variable.actionNoVariableSupport="Getting variable values from %1 actions is not supported!"
|
||||||
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="Getting variable values from %1 conditions is not supported!"
|
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="Getting variable values from %1 conditions is not supported!"
|
||||||
AdvSceneSwitcher.action.variable.currentSegmentValue="Current value:"
|
AdvSceneSwitcher.action.variable.currentSegmentValue="Current value:"
|
||||||
AdvSceneSwitcher.action.variable.entry="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}{{envVariableName}}{{scenes}}{{tempVars}}{{sceneItemIndex}}"
|
AdvSceneSwitcher.action.variable.entry="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}{{envVariableName}}{{scenes}}{{tempVars}}"
|
||||||
AdvSceneSwitcher.action.variable.entry.substringIndex="Substring start:{{subStringStart}}Substring size:{{subStringSize}}"
|
AdvSceneSwitcher.action.variable.entry.substringIndex="Substring start:{{subStringStart}}Substring size:{{subStringSize}}"
|
||||||
AdvSceneSwitcher.action.variable.entry.substringRegex="Assign value of{{regexMatchIdx}}match using regular expression:"
|
AdvSceneSwitcher.action.variable.entry.substringRegex="Assign value of{{regexMatchIdx}}match using regular expression:"
|
||||||
AdvSceneSwitcher.action.variable.entry.findAndReplace="{{findStr}}{{replaceStr}}"
|
AdvSceneSwitcher.action.variable.entry.findAndReplace="{{findStr}}{{replaceStr}}"
|
||||||
@@ -859,15 +853,15 @@ AdvSceneSwitcher.action.sceneLock.type.unlock="unlock"
|
|||||||
AdvSceneSwitcher.action.sceneLock.type.toggle="toggle lock of"
|
AdvSceneSwitcher.action.sceneLock.type.toggle="toggle lock of"
|
||||||
AdvSceneSwitcher.action.sceneLock.entry="On{{scenes}}{{actions}}{{sources}}"
|
AdvSceneSwitcher.action.sceneLock.entry="On{{scenes}}{{actions}}{{sources}}"
|
||||||
AdvSceneSwitcher.action.twitch="Twitch"
|
AdvSceneSwitcher.action.twitch="Twitch"
|
||||||
AdvSceneSwitcher.action.twitch.type.channel.info.title.set="Set stream title"
|
AdvSceneSwitcher.action.twitch.type.title="Set stream title"
|
||||||
AdvSceneSwitcher.action.twitch.type.channel.info.category.set="Set stream category"
|
AdvSceneSwitcher.action.twitch.type.category="Set stream category"
|
||||||
AdvSceneSwitcher.action.twitch.type.raid.start="Start raid"
|
AdvSceneSwitcher.action.twitch.type.marker="Create stream marker"
|
||||||
AdvSceneSwitcher.action.twitch.type.commercial.start="Start commercial"
|
AdvSceneSwitcher.action.twitch.type.clip="Create stream clip"
|
||||||
AdvSceneSwitcher.action.twitch.type.marker.create="Create stream marker"
|
AdvSceneSwitcher.action.twitch.type.commercial="Start commercial with duration"
|
||||||
AdvSceneSwitcher.action.twitch.type.clip.create="Create stream clip"
|
AdvSceneSwitcher.action.twitch.type.announcement="Send chat announcement"
|
||||||
AdvSceneSwitcher.action.twitch.type.chat.announcement.send="Send chat announcement"
|
AdvSceneSwitcher.action.twitch.type.emoteOnlyEnable="Enable chat's emote-only mode"
|
||||||
AdvSceneSwitcher.action.twitch.type.chat.emoteOnly.enable="Enable chat's emote-only mode"
|
AdvSceneSwitcher.action.twitch.type.emoteOnlyDisable="Disable chat's emote-only mode"
|
||||||
AdvSceneSwitcher.action.twitch.type.chat.emoteOnly.disable="Disable chat's emote-only mode"
|
AdvSceneSwitcher.action.twitch.type.raid="Raid channel"
|
||||||
AdvSceneSwitcher.action.twitch.type.sendChatMessage="Send chat message"
|
AdvSceneSwitcher.action.twitch.type.sendChatMessage="Send chat message"
|
||||||
AdvSceneSwitcher.action.twitch.categorySelectionDisabled="Cannot select category without selecting a Twitch account first!"
|
AdvSceneSwitcher.action.twitch.categorySelectionDisabled="Cannot select category without selecting a Twitch account first!"
|
||||||
AdvSceneSwitcher.action.twitch.entry.default="On{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{channel}}"
|
AdvSceneSwitcher.action.twitch.entry.default="On{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{channel}}"
|
||||||
@@ -881,12 +875,6 @@ AdvSceneSwitcher.action.twitch.announcement.blue="Blue"
|
|||||||
AdvSceneSwitcher.action.twitch.announcement.green="Green"
|
AdvSceneSwitcher.action.twitch.announcement.green="Green"
|
||||||
AdvSceneSwitcher.action.twitch.announcement.orange="Orange"
|
AdvSceneSwitcher.action.twitch.announcement.orange="Orange"
|
||||||
AdvSceneSwitcher.action.twitch.announcement.purple="Purple"
|
AdvSceneSwitcher.action.twitch.announcement.purple="Purple"
|
||||||
AdvSceneSwitcher.action.clipboard="Clipboard"
|
|
||||||
AdvSceneSwitcher.action.clipboard.type.copy.text="Copy text"
|
|
||||||
AdvSceneSwitcher.action.clipboard.type.copy.image="Copy image"
|
|
||||||
AdvSceneSwitcher.action.clipboard.copy.text.text.placeholder="Enter text"
|
|
||||||
AdvSceneSwitcher.action.clipboard.copy.image.url.placeholder="Enter direct image URL"
|
|
||||||
AdvSceneSwitcher.action.clipboard.copy.image.url.tooltip="Currently supported formats: PNG, JPG/JPEG, BMP, GIF."
|
|
||||||
|
|
||||||
; Hotkey
|
; Hotkey
|
||||||
AdvSceneSwitcher.hotkey.startSwitcherHotkey="Start the Advanced Scene Switcher"
|
AdvSceneSwitcher.hotkey.startSwitcherHotkey="Start the Advanced Scene Switcher"
|
||||||
@@ -1040,10 +1028,14 @@ AdvSceneSwitcher.twitchToken.request.notSet="Account is not connected!"
|
|||||||
AdvSceneSwitcher.twitchToken.permissions="Token permissions:"
|
AdvSceneSwitcher.twitchToken.permissions="Token permissions:"
|
||||||
AdvSceneSwitcher.twitchToken.permissionsInsufficient="Permissions of selected token are insufficient to perform selected action!"
|
AdvSceneSwitcher.twitchToken.permissionsInsufficient="Permissions of selected token are insufficient to perform selected action!"
|
||||||
AdvSceneSwitcher.twitchToken.channel.broadcast.manage="Manage a channel’s broadcast configuration, including updating channel configuration and managing stream markers and stream tags."
|
AdvSceneSwitcher.twitchToken.channel.broadcast.manage="Manage a channel’s broadcast configuration, including updating channel configuration and managing stream markers and stream tags."
|
||||||
|
AdvSceneSwitcher.twitchToken.channel.commercial.edit="Run commercials on a channel."
|
||||||
|
AdvSceneSwitcher.twitchToken.clips.edit="Create clips from channel's broadcasts."
|
||||||
|
AdvSceneSwitcher.twitchToken.moderator.announcements.manage="Manage channel's chat announcements."
|
||||||
|
AdvSceneSwitcher.twitchToken.moderator.chat.settings.manage="Manage channel's chat settings, such as emote-only or slow mode."
|
||||||
|
AdvSceneSwitcher.twitchToken.channel.raid="Manage channel's raids."
|
||||||
AdvSceneSwitcher.twitchToken.channel.subscriptions.read="Read channel's subscribers list and info."
|
AdvSceneSwitcher.twitchToken.channel.subscriptions.read="Read channel's subscribers list and info."
|
||||||
AdvSceneSwitcher.twitchToken.moderator.followers.read="Read the followers of a broadcaster."
|
AdvSceneSwitcher.twitchToken.moderator.followers.read="Read the followers of a broadcaster."
|
||||||
AdvSceneSwitcher.twitchToken.bits.read="Read channel's Bits information."
|
AdvSceneSwitcher.twitchToken.bits.read="Read channel's Bits information."
|
||||||
AdvSceneSwitcher.twitchToken.channel.raids.manage="Manage channel's raids."
|
|
||||||
AdvSceneSwitcher.twitchToken.moderator.shoutouts.read="Read channel's shoutouts."
|
AdvSceneSwitcher.twitchToken.moderator.shoutouts.read="Read channel's shoutouts."
|
||||||
AdvSceneSwitcher.twitchToken.moderator.shoutouts.manage="Manage channel's shoutouts."
|
AdvSceneSwitcher.twitchToken.moderator.shoutouts.manage="Manage channel's shoutouts."
|
||||||
AdvSceneSwitcher.twitchToken.channel.polls.read="Read channel's polls' state."
|
AdvSceneSwitcher.twitchToken.channel.polls.read="Read channel's polls' state."
|
||||||
@@ -1058,17 +1050,7 @@ AdvSceneSwitcher.twitchToken.moderator.shieldMode.manage="Manage channel's Shiel
|
|||||||
AdvSceneSwitcher.twitchToken.channel.redemptions.read="Read channel's point rewards and their redemptions."
|
AdvSceneSwitcher.twitchToken.channel.redemptions.read="Read channel's point rewards and their redemptions."
|
||||||
AdvSceneSwitcher.twitchToken.channel.redemptions.manage="Manage channel's point rewards and their redemptions."
|
AdvSceneSwitcher.twitchToken.channel.redemptions.manage="Manage channel's point rewards and their redemptions."
|
||||||
AdvSceneSwitcher.twitchToken.channel.moderate="Moderate the channel."
|
AdvSceneSwitcher.twitchToken.channel.moderate="Moderate the channel."
|
||||||
AdvSceneSwitcher.twitchToken.moderator.bannedUsers.manage="Manage channel's banned users."
|
AdvSceneSwitcher.twitchToken.channel.moderation.read="Read channel's moderation data."
|
||||||
AdvSceneSwitcher.twitchToken.user.blockedUsers.manage="Manage user's blocked users."
|
|
||||||
AdvSceneSwitcher.twitchToken.moderation.read="Read channel's moderation data."
|
|
||||||
AdvSceneSwitcher.twitchToken.channel.moderators.manage="Manage channel's moderators."
|
|
||||||
AdvSceneSwitcher.twitchToken.channel.vips.manage="Manage channel's VIPs."
|
|
||||||
AdvSceneSwitcher.twitchToken.channel.commercial.edit="Run commercials on a channel."
|
|
||||||
AdvSceneSwitcher.twitchToken.channel.ads.manage="Manage channel's commercials."
|
|
||||||
AdvSceneSwitcher.twitchToken.clips.edit="Create clips from channel's broadcasts."
|
|
||||||
AdvSceneSwitcher.twitchToken.moderator.announcements.manage="Manage channel's chat announcements."
|
|
||||||
AdvSceneSwitcher.twitchToken.moderator.chat.settings.manage="Manage channel's chat settings, such as emote-only or slow mode."
|
|
||||||
AdvSceneSwitcher.twitchToken.user.whispers.manage="Manage user's whispers."
|
|
||||||
AdvSceneSwitcher.twitchToken.chat.read="View live stream chat messages."
|
AdvSceneSwitcher.twitchToken.chat.read="View live stream chat messages."
|
||||||
AdvSceneSwitcher.twitchToken.chat.edit="Send live stream chat messages."
|
AdvSceneSwitcher.twitchToken.chat.edit="Send live stream chat messages."
|
||||||
|
|
||||||
@@ -1294,9 +1276,9 @@ AdvSceneSwitcher.tempVar.twitch.started_at.shoutoutReceived="Shoutout time"
|
|||||||
AdvSceneSwitcher.tempVar.twitch.started_at.shoutoutReceived.description="The UTC timestamp (in RFC3339 format) of when the moderator sent the Shoutout."
|
AdvSceneSwitcher.tempVar.twitch.started_at.shoutoutReceived.description="The UTC timestamp (in RFC3339 format) of when the moderator sent the Shoutout."
|
||||||
|
|
||||||
AdvSceneSwitcher.tempVar.twitch.id.reward="Reward id"
|
AdvSceneSwitcher.tempVar.twitch.id.reward="Reward id"
|
||||||
AdvSceneSwitcher.tempVar.twitch.user_id.reward="User id redeeming the reward"
|
AdvSceneSwitcher.tempVar.twitch.user_id.reward="User id redeeming reward"
|
||||||
AdvSceneSwitcher.tempVar.twitch.user_login.reward="User login redeeming the reward"
|
AdvSceneSwitcher.tempVar.twitch.user_login.reward="User login redeeming reward"
|
||||||
AdvSceneSwitcher.tempVar.twitch.user_name.reward="User name redeeming the reward"
|
AdvSceneSwitcher.tempVar.twitch.user_name.reward="User login redeeming reward"
|
||||||
AdvSceneSwitcher.tempVar.twitch.user_input.reward="User input for reward"
|
AdvSceneSwitcher.tempVar.twitch.user_input.reward="User input for reward"
|
||||||
AdvSceneSwitcher.tempVar.twitch.reward.reward="Reward Information"
|
AdvSceneSwitcher.tempVar.twitch.reward.reward="Reward Information"
|
||||||
AdvSceneSwitcher.tempVar.twitch.reward.reward.description="Basic information about the reward that was redeemed, at the time it was redeemed."
|
AdvSceneSwitcher.tempVar.twitch.reward.reward.description="Basic information about the reward that was redeemed, at the time it was redeemed."
|
||||||
@@ -1431,20 +1413,6 @@ AdvSceneSwitcher.tempVar.twitch.chatter="User login"
|
|||||||
AdvSceneSwitcher.tempVar.twitch.chatter.description="The user login of the person who sent the chat message."
|
AdvSceneSwitcher.tempVar.twitch.chatter.description="The user login of the person who sent the chat message."
|
||||||
AdvSceneSwitcher.tempVar.twitch.chat_message="Chat message"
|
AdvSceneSwitcher.tempVar.twitch.chat_message="Chat message"
|
||||||
|
|
||||||
AdvSceneSwitcher.tempVar.twitch.from_broadcaster_user_id.raid="Raid creator user ID"
|
|
||||||
AdvSceneSwitcher.tempVar.twitch.from_broadcaster_user_id.raid.description="The broadcaster ID that created the raid."
|
|
||||||
AdvSceneSwitcher.tempVar.twitch.from_broadcaster_user_login.raid="Raid creator user login"
|
|
||||||
AdvSceneSwitcher.tempVar.twitch.from_broadcaster_user_login.raid.description="The broadcaster login that created the raid."
|
|
||||||
AdvSceneSwitcher.tempVar.twitch.from_broadcaster_user_name.raid="Raid creator user name"
|
|
||||||
AdvSceneSwitcher.tempVar.twitch.from_broadcaster_user_name.raid.description="The broadcaster display name that created the raid."
|
|
||||||
AdvSceneSwitcher.tempVar.twitch.to_broadcaster_user_id.raid="Raid receiver user ID"
|
|
||||||
AdvSceneSwitcher.tempVar.twitch.to_broadcaster_user_id.raid.description="The broadcaster ID that created the raid."
|
|
||||||
AdvSceneSwitcher.tempVar.twitch.to_broadcaster_user_login.raid="Raid receiver user login"
|
|
||||||
AdvSceneSwitcher.tempVar.twitch.to_broadcaster_user_login.raid.description="The broadcaster login that created the raid."
|
|
||||||
AdvSceneSwitcher.tempVar.twitch.to_broadcaster_user_name.raid="Raid receiver user name"
|
|
||||||
AdvSceneSwitcher.tempVar.twitch.to_broadcaster_user_name.raid.description="The broadcaster display name that created the raid."
|
|
||||||
AdvSceneSwitcher.tempVar.twitch.viewers.raid="Raid participants"
|
|
||||||
AdvSceneSwitcher.tempVar.twitch.viewers.raid.description="The number of viewers in the raid."
|
|
||||||
|
|
||||||
AdvSceneSwitcher.tempVar.audio.output_volume="Output volume"
|
AdvSceneSwitcher.tempVar.audio.output_volume="Output volume"
|
||||||
AdvSceneSwitcher.tempVar.audio.output_volume.description="The volume the audio source is outputting."
|
AdvSceneSwitcher.tempVar.audio.output_volume.description="The volume the audio source is outputting."
|
||||||
@@ -1455,11 +1423,6 @@ AdvSceneSwitcher.tempVar.audio.sync_offset="Source audio sync offset"
|
|||||||
AdvSceneSwitcher.tempVar.audio.monitor="Source audio monitor type"
|
AdvSceneSwitcher.tempVar.audio.monitor="Source audio monitor type"
|
||||||
AdvSceneSwitcher.tempVar.audio.balance="Source audio balance"
|
AdvSceneSwitcher.tempVar.audio.balance="Source audio balance"
|
||||||
|
|
||||||
AdvSceneSwitcher.tempVar.clipboard.mimeType.primary="Primary clipboard item MIME type"
|
|
||||||
AdvSceneSwitcher.tempVar.clipboard.mimeType.primary.description="Highest priority MIME type of the current item stored in clipboard, if available."
|
|
||||||
AdvSceneSwitcher.tempVar.clipboard.mimeType.all="All clipboard item MIME types"
|
|
||||||
AdvSceneSwitcher.tempVar.clipboard.mimeType.all.description="All MIME types of the current item stored in clipboard separated with space, if available."
|
|
||||||
|
|
||||||
AdvSceneSwitcher.tempVar.scene.current="Current scene"
|
AdvSceneSwitcher.tempVar.scene.current="Current scene"
|
||||||
AdvSceneSwitcher.tempVar.scene.previous="Previous scene"
|
AdvSceneSwitcher.tempVar.scene.previous="Previous scene"
|
||||||
AdvSceneSwitcher.tempVar.scene.preview="Preview scene"
|
AdvSceneSwitcher.tempVar.scene.preview="Preview scene"
|
||||||
@@ -1480,33 +1443,6 @@ AdvSceneSwitcher.tempVar.date.minute="Minute"
|
|||||||
AdvSceneSwitcher.tempVar.date.second="Second"
|
AdvSceneSwitcher.tempVar.date.second="Second"
|
||||||
AdvSceneSwitcher.tempVar.date.dayOfWeek="Day of week"
|
AdvSceneSwitcher.tempVar.date.dayOfWeek="Day of week"
|
||||||
|
|
||||||
AdvSceneSwitcher.tempVar.midi.type="Message type"
|
|
||||||
AdvSceneSwitcher.tempVar.midi.channel="Channel"
|
|
||||||
AdvSceneSwitcher.tempVar.midi.note="Note"
|
|
||||||
AdvSceneSwitcher.tempVar.midi.value1="Value 1"
|
|
||||||
AdvSceneSwitcher.tempVar.midi.value2="Value 2"
|
|
||||||
|
|
||||||
AdvSceneSwitcher.tempVar.macro.runCount="Run count"
|
|
||||||
AdvSceneSwitcher.tempVar.macro.runCount.description="The number of times a macro was executed."
|
|
||||||
AdvSceneSwitcher.tempVar.macro.matchedCount="Matched count"
|
|
||||||
AdvSceneSwitcher.tempVar.macro.matchedCount.description="The number of macros of which the condition state was true."
|
|
||||||
|
|
||||||
AdvSceneSwitcher.tempVar.process.name="Process name"
|
|
||||||
|
|
||||||
AdvSceneSwitcher.tempVar.recording.durationSeconds="Recording duration"
|
|
||||||
AdvSceneSwitcher.tempVar.recording.durationSeconds.description="Recording duration in seconds.\nThis value does not change while the recording is paused and will be reset to zero if the recording is stopped."
|
|
||||||
|
|
||||||
AdvSceneSwitcher.tempVar.video.patternCount="Pattern count"
|
|
||||||
AdvSceneSwitcher.tempVar.video.patternCount.description="The number of times the given pattern has been found in a given video input frame."
|
|
||||||
AdvSceneSwitcher.tempVar.video.objectCount="Object count"
|
|
||||||
AdvSceneSwitcher.tempVar.video.objectCount.description="The number of objects the given model has identified in a given video input frame."
|
|
||||||
AdvSceneSwitcher.tempVar.video.brightness="Average brightness"
|
|
||||||
AdvSceneSwitcher.tempVar.video.brightness.description="The average brightness in a given video input frame in a range from 0 to 1 (dark to bright)."
|
|
||||||
AdvSceneSwitcher.tempVar.video.text="OCR text"
|
|
||||||
AdvSceneSwitcher.tempVar.video.text.description="The text detected in a given video input frame."
|
|
||||||
AdvSceneSwitcher.tempVar.video.color="Average color"
|
|
||||||
AdvSceneSwitcher.tempVar.video.color.description="The average RGB color in a given video input frame in HexArgb format."
|
|
||||||
|
|
||||||
AdvSceneSwitcher.selectScene="--select scene--"
|
AdvSceneSwitcher.selectScene="--select scene--"
|
||||||
AdvSceneSwitcher.selectPreviousScene="Previous Scene"
|
AdvSceneSwitcher.selectPreviousScene="Previous Scene"
|
||||||
AdvSceneSwitcher.selectCurrentScene="Current Scene"
|
AdvSceneSwitcher.selectCurrentScene="Current Scene"
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ AdvSceneSwitcher.condition.file.entry.line3="{{checkModificationDate}}{{checkFil
|
|||||||
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"
|
||||||
|
AdvSceneSwitcher.condition.media.matchOnChange="Solo coincidir con el cambio (Nota: esta opción se eliminará en una versión futura; use modificadores de duración en su lugar)"
|
||||||
AdvSceneSwitcher.condition.media.inconsistencyInfo="Desafortunadamente, no todos los tipos de fuentes de medios se comportan de la misma manera (p. ej., fuente de medios frente a estado \"Detenido\" de fuente de video VLC).\n¡Así que experimente lo que funciona para su configuración!"
|
AdvSceneSwitcher.condition.media.inconsistencyInfo="Desafortunadamente, no todos los tipos de fuentes de medios se comportan de la misma manera (p. ej., fuente de medios frente a estado \"Detenido\" de fuente de video VLC).\n¡Así que experimente lo que funciona para su configuración!"
|
||||||
AdvSceneSwitcher.condition.media.entry="El estado de{{sourceTypes}}{{mediaSources}}{{scenes}}es{{states}}y{{timeRestrictions}}{{time}}"
|
AdvSceneSwitcher.condition.media.entry="El estado de{{sourceTypes}}{{mediaSources}}{{scenes}}es{{states}}y{{timeRestrictions}}{{time}}"
|
||||||
AdvSceneSwitcher.condition.video="Video"
|
AdvSceneSwitcher.condition.video="Video"
|
||||||
@@ -181,8 +182,9 @@ AdvSceneSwitcher.condition.record="Grabación"
|
|||||||
AdvSceneSwitcher.condition.record.state.start="Grabación en ejecución"
|
AdvSceneSwitcher.condition.record.state.start="Grabación en ejecución"
|
||||||
AdvSceneSwitcher.condition.record.state.pause="Grabación en pausa"
|
AdvSceneSwitcher.condition.record.state.pause="Grabación en pausa"
|
||||||
AdvSceneSwitcher.condition.record.state.stop="Grabación detenida"
|
AdvSceneSwitcher.condition.record.state.stop="Grabación detenida"
|
||||||
|
AdvSceneSwitcher.condition.record.entry="{{recordState}}"
|
||||||
AdvSceneSwitcher.condition.process="Proceso"
|
AdvSceneSwitcher.condition.process="Proceso"
|
||||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}se está ejecutando{{focused}}y está enfocado"
|
AdvSceneSwitcher.condition.process.entry="{{processes}} se está ejecutando {{focused}} y está enfocado"
|
||||||
AdvSceneSwitcher.condition.idle="Inactivo"
|
AdvSceneSwitcher.condition.idle="Inactivo"
|
||||||
AdvSceneSwitcher.condition.idle.entry="No hay entradas de teclado o ratón durante {{duration}}"
|
AdvSceneSwitcher.condition.idle.entry="No hay entradas de teclado o ratón durante {{duration}}"
|
||||||
AdvSceneSwitcher.condition.pluginState="Estado del complemento"
|
AdvSceneSwitcher.condition.pluginState="Estado del complemento"
|
||||||
|
|||||||
@@ -197,6 +197,7 @@ AdvSceneSwitcher.condition.media="Média"
|
|||||||
AdvSceneSwitcher.condition.media.source="Source"
|
AdvSceneSwitcher.condition.media.source="Source"
|
||||||
AdvSceneSwitcher.condition.media.anyOnScene="Toute source média sur la scène"
|
AdvSceneSwitcher.condition.media.anyOnScene="Toute source média sur la scène"
|
||||||
AdvSceneSwitcher.condition.media.allOnScene="Toutes les sources média sur la scène"
|
AdvSceneSwitcher.condition.media.allOnScene="Toutes les sources média sur la scène"
|
||||||
|
AdvSceneSwitcher.condition.media.matchOnChange="Ne correspondre qu'au changement (Remarque : Cette option sera supprimée dans une version future - veuillez plutôt utiliser les modificateurs de durée)"
|
||||||
AdvSceneSwitcher.condition.media.inconsistencyInfo="Malheureusement, toutes les sources média ne se comportent pas de la même manière (par exemple, l'état \"Arrêté\" de la source Media par rapport à la source Vidéo VLC).\nPar conséquent, veuillez expérimenter ce qui fonctionne le mieux pour votre configuration !"
|
AdvSceneSwitcher.condition.media.inconsistencyInfo="Malheureusement, toutes les sources média ne se comportent pas de la même manière (par exemple, l'état \"Arrêté\" de la source Media par rapport à la source Vidéo VLC).\nPar conséquent, veuillez expérimenter ce qui fonctionne le mieux pour votre configuration !"
|
||||||
AdvSceneSwitcher.condition.media.entry="{{sourceTypes}}{{mediaSources}}{{scenes}}l'état est{{states}}et{{timeRestrictions}}{{time}}"
|
AdvSceneSwitcher.condition.media.entry="{{sourceTypes}}{{mediaSources}}{{scenes}}l'état est{{states}}et{{timeRestrictions}}{{time}}"
|
||||||
AdvSceneSwitcher.condition.video="Vidéo"
|
AdvSceneSwitcher.condition.video="Vidéo"
|
||||||
@@ -285,7 +286,7 @@ AdvSceneSwitcher.condition.record.state.start="Enregistrement en cours"
|
|||||||
AdvSceneSwitcher.condition.record.state.pause="Enregistrement en pause"
|
AdvSceneSwitcher.condition.record.state.pause="Enregistrement en pause"
|
||||||
AdvSceneSwitcher.condition.record.state.stop="Arrêt de l'enregistrement"
|
AdvSceneSwitcher.condition.record.state.stop="Arrêt de l'enregistrement"
|
||||||
AdvSceneSwitcher.condition.process="Processus"
|
AdvSceneSwitcher.condition.process="Processus"
|
||||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}en cours d'exécution{{focused}}et est au premier plan"
|
AdvSceneSwitcher.condition.process.entry="{{processes}}en cours d'exécution{{focused}}et est au premier plan"
|
||||||
AdvSceneSwitcher.condition.process.entry.focus="Processus au premier plan actuel :{{focusProcess}}"
|
AdvSceneSwitcher.condition.process.entry.focus="Processus au premier plan actuel :{{focusProcess}}"
|
||||||
AdvSceneSwitcher.condition.idle="Inactif"
|
AdvSceneSwitcher.condition.idle="Inactif"
|
||||||
AdvSceneSwitcher.condition.idle.entry="Aucune entrée de clavier ou de souris pendant{{duration}}"
|
AdvSceneSwitcher.condition.idle.entry="Aucune entrée de clavier ou de souris pendant{{duration}}"
|
||||||
@@ -735,10 +736,11 @@ AdvSceneSwitcher.action.sceneLock.type.unlock="déverrouiller"
|
|||||||
AdvSceneSwitcher.action.sceneLock.type.toggle="basculer le verrouillage de"
|
AdvSceneSwitcher.action.sceneLock.type.toggle="basculer le verrouillage de"
|
||||||
AdvSceneSwitcher.action.sceneLock.entry="Sur{{scenes}}{{actions}}{{sources}}"
|
AdvSceneSwitcher.action.sceneLock.entry="Sur{{scenes}}{{actions}}{{sources}}"
|
||||||
AdvSceneSwitcher.action.twitch="Twitch"
|
AdvSceneSwitcher.action.twitch="Twitch"
|
||||||
AdvSceneSwitcher.action.twitch.type.channel.info.title.set="Définir le titre du flux"
|
AdvSceneSwitcher.action.twitch.type.title="Définir le titre du flux"
|
||||||
AdvSceneSwitcher.action.twitch.type.channel.info.category.set="Définir la catégorie du flux"
|
AdvSceneSwitcher.action.twitch.type.category="Définir la catégorie du flux"
|
||||||
AdvSceneSwitcher.action.twitch.type.commercial.start="Démarrer une publicité d'une durée de"
|
AdvSceneSwitcher.action.twitch.type.commercial="Démarrer une publicité d'une durée de"
|
||||||
AdvSceneSwitcher.action.twitch.categorySelectionDisabled="Impossible de sélectionner une catégorie sans avoir d'abord sélectionné un compte Twitch !"
|
AdvSceneSwitcher.action.twitch.categorySelectionDisabled="Impossible de sélectionner une catégorie sans avoir d'abord sélectionné un compte Twitch !"
|
||||||
|
AdvSceneSwitcher.action.twitch.entry.line1="Sur{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{channel}}"
|
||||||
|
|
||||||
; Transition Tab
|
; Transition Tab
|
||||||
AdvSceneSwitcher.transitionTab.title="Transition"
|
AdvSceneSwitcher.transitionTab.title="Transition"
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ AdvSceneSwitcher.condition.record.state.start="Запись запущена"
|
|||||||
AdvSceneSwitcher.condition.record.state.pause="Запись приостановлена"
|
AdvSceneSwitcher.condition.record.state.pause="Запись приостановлена"
|
||||||
AdvSceneSwitcher.condition.record.state.stop="Запись остановлена"
|
AdvSceneSwitcher.condition.record.state.stop="Запись остановлена"
|
||||||
AdvSceneSwitcher.condition.process="Процесс"
|
AdvSceneSwitcher.condition.process="Процесс"
|
||||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}запущен{{focused}}и сфокусирован"
|
AdvSceneSwitcher.condition.process.entry="{{processes}} запущен {{focused}} и сфокусирован"
|
||||||
AdvSceneSwitcher.condition.idle="Простой"
|
AdvSceneSwitcher.condition.idle="Простой"
|
||||||
AdvSceneSwitcher.condition.idle.entry="Не было ни клавиатуры, ни мыши в течении{{duration}}"
|
AdvSceneSwitcher.condition.idle.entry="Не было ни клавиатуры, ни мыши в течении{{duration}}"
|
||||||
AdvSceneSwitcher.condition.pluginState="Состояние плагина"
|
AdvSceneSwitcher.condition.pluginState="Состояние плагина"
|
||||||
|
|||||||
@@ -119,6 +119,7 @@ AdvSceneSwitcher.condition.file.entry.line3="{{checkModificationDate}}{{checkFil
|
|||||||
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ı "
|
||||||
|
AdvSceneSwitcher.condition.media.matchOnChange="Yalnızca değişiklikle eşleştirin (Not: Bu seçenek gelecekteki bir sürümde kaldırılacaktır - lütfen bunun yerine zaman kısıtlamalarını kullanın)"
|
||||||
AdvSceneSwitcher.condition.media.entry="{{sourceTypes}}{{mediaSources}}{{scenes}}durumu{{states}}ve{{timeRestrictions}}{{time}}"
|
AdvSceneSwitcher.condition.media.entry="{{sourceTypes}}{{mediaSources}}{{scenes}}durumu{{states}}ve{{timeRestrictions}}{{time}}"
|
||||||
AdvSceneSwitcher.condition.video="Video"
|
AdvSceneSwitcher.condition.video="Video"
|
||||||
AdvSceneSwitcher.condition.video.condition.match="Tam olarak eşleşir"
|
AdvSceneSwitcher.condition.video.condition.match="Tam olarak eşleşir"
|
||||||
@@ -158,8 +159,9 @@ AdvSceneSwitcher.condition.record="Kayıt"
|
|||||||
AdvSceneSwitcher.condition.record.state.start="Kayıt Çalışıyor"
|
AdvSceneSwitcher.condition.record.state.start="Kayıt Çalışıyor"
|
||||||
AdvSceneSwitcher.condition.record.state.pause="Kayıt durakladı"
|
AdvSceneSwitcher.condition.record.state.pause="Kayıt durakladı"
|
||||||
AdvSceneSwitcher.condition.record.state.stop="Kayıt durdu"
|
AdvSceneSwitcher.condition.record.state.stop="Kayıt durdu"
|
||||||
|
AdvSceneSwitcher.condition.record.entry="{{recordState}}"
|
||||||
AdvSceneSwitcher.condition.process="İşlem"
|
AdvSceneSwitcher.condition.process="İşlem"
|
||||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}çalışıyor{{focused}}ve odaklandı"
|
AdvSceneSwitcher.condition.process.entry="{{processes}} çalışıyor {{focused}} ve odaklandı"
|
||||||
AdvSceneSwitcher.condition.idle="Boşta"
|
AdvSceneSwitcher.condition.idle="Boşta"
|
||||||
AdvSceneSwitcher.condition.idle.entry="...için klavye veya fare girişi yok {{duration}}"
|
AdvSceneSwitcher.condition.idle.entry="...için klavye veya fare girişi yok {{duration}}"
|
||||||
AdvSceneSwitcher.condition.pluginState="Eklenti durumu"
|
AdvSceneSwitcher.condition.pluginState="Eklenti durumu"
|
||||||
|
|||||||
@@ -185,6 +185,7 @@ AdvSceneSwitcher.condition.media="媒体"
|
|||||||
AdvSceneSwitcher.condition.media.source="源"
|
AdvSceneSwitcher.condition.media.source="源"
|
||||||
AdvSceneSwitcher.condition.media.anyOnScene="任何媒体源"
|
AdvSceneSwitcher.condition.media.anyOnScene="任何媒体源"
|
||||||
AdvSceneSwitcher.condition.media.allOnScene="所有媒体源"
|
AdvSceneSwitcher.condition.media.allOnScene="所有媒体源"
|
||||||
|
AdvSceneSwitcher.condition.media.matchOnChange="仅在更改时匹配(注意:此选项将在未来版本中删除-请改用时间限制)"
|
||||||
AdvSceneSwitcher.condition.media.inconsistencyInfo="不幸的是,并非所有媒体源类型的行为都相同(例如,媒体源与VLC视频源“停止”状态)。\n所以,请尝试适合您的设置!"
|
AdvSceneSwitcher.condition.media.inconsistencyInfo="不幸的是,并非所有媒体源类型的行为都相同(例如,媒体源与VLC视频源“停止”状态)。\n所以,请尝试适合您的设置!"
|
||||||
AdvSceneSwitcher.condition.media.entry="{{sourceTypes}}{{mediaSources}}{{scenes}} 的状态是 {{states}} 和 {{timeRestrictions}}{{time}}"
|
AdvSceneSwitcher.condition.media.entry="{{sourceTypes}}{{mediaSources}}{{scenes}} 的状态是 {{states}} 和 {{timeRestrictions}}{{time}}"
|
||||||
AdvSceneSwitcher.condition.video="视频"
|
AdvSceneSwitcher.condition.video="视频"
|
||||||
@@ -266,8 +267,9 @@ AdvSceneSwitcher.condition.record="录制"
|
|||||||
AdvSceneSwitcher.condition.record.state.start="录制运行中"
|
AdvSceneSwitcher.condition.record.state.start="录制运行中"
|
||||||
AdvSceneSwitcher.condition.record.state.pause="录制暂停"
|
AdvSceneSwitcher.condition.record.state.pause="录制暂停"
|
||||||
AdvSceneSwitcher.condition.record.state.stop="录制停止"
|
AdvSceneSwitcher.condition.record.state.stop="录制停止"
|
||||||
|
AdvSceneSwitcher.condition.record.entry="{{recordState}}"
|
||||||
AdvSceneSwitcher.condition.process="进程"
|
AdvSceneSwitcher.condition.process="进程"
|
||||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}是正在运行{{focused}}并且是获得焦点"
|
AdvSceneSwitcher.condition.process.entry="{{processes}} 是正在运行 {{focused}} 并且是获得焦点"
|
||||||
AdvSceneSwitcher.condition.process.entry.focus="当前焦点进程: {{focusProcess}}"
|
AdvSceneSwitcher.condition.process.entry.focus="当前焦点进程: {{focusProcess}}"
|
||||||
AdvSceneSwitcher.condition.idle="闲置检测"
|
AdvSceneSwitcher.condition.idle="闲置检测"
|
||||||
AdvSceneSwitcher.condition.idle.entry="没有键盘或鼠标输入{{duration}}"
|
AdvSceneSwitcher.condition.idle.entry="没有键盘或鼠标输入{{duration}}"
|
||||||
@@ -649,6 +651,7 @@ AdvSceneSwitcher.action.variable.invalidSelection="无效选择!"
|
|||||||
AdvSceneSwitcher.action.variable.actionNoVariableSupport="不支持从 %1 个操作获取变量值!"
|
AdvSceneSwitcher.action.variable.actionNoVariableSupport="不支持从 %1 个操作获取变量值!"
|
||||||
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="不支持从 %1 条件中获取变量值!"
|
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="不支持从 %1 条件中获取变量值!"
|
||||||
AdvSceneSwitcher.action.variable.currentSegmentValue="当前值:"
|
AdvSceneSwitcher.action.variable.currentSegmentValue="当前值:"
|
||||||
|
AdvSceneSwitcher.action.variable.entry="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}{{envVariableName}}{{scenes}}{{tempVars}}"
|
||||||
AdvSceneSwitcher.action.variable.entry.substringIndex="子字符串开始:{{subStringStart}} 子字符串大小:{{subStringSize}}"
|
AdvSceneSwitcher.action.variable.entry.substringIndex="子字符串开始:{{subStringStart}} 子字符串大小:{{subStringSize}}"
|
||||||
AdvSceneSwitcher.action.variable.entry.substringRegex="使用正则表达式为 {{regexMatchIdx}} 匹配的值:"
|
AdvSceneSwitcher.action.variable.entry.substringRegex="使用正则表达式为 {{regexMatchIdx}} 匹配的值:"
|
||||||
AdvSceneSwitcher.action.variable.entry.findAndReplace="{{findStr}}{{replaceStr}}"
|
AdvSceneSwitcher.action.variable.entry.findAndReplace="{{findStr}}{{replaceStr}}"
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
<?xml version="1.0"?>
|
|
||||||
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid meet" version="1.1">
|
|
||||||
<!-- Created with SVG-edit - https://github.com/SVG-Edit/svgedit-->
|
|
||||||
|
|
||||||
<g class="layer">
|
|
||||||
<title>Layer 1</title>
|
|
||||||
<rect fill="#fefefe" height="2.25" id="svg_1" stroke="#fefefe" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" transform="matrix(1, 0, 0, 1, 0, 0)" width="13" x="1.5" y="4"/>
|
|
||||||
<rect fill="#fefefe" height="2.25" id="svg_2" stroke="#fefefe" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" transform="matrix(1, 0, 0, 1, 0, 0)" width="13" x="1.5" y="10"/>
|
|
||||||
<rect fill="#fefefe" height="1" id="svg_4" stroke="#fefefe" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" transform="matrix(0.341951, -0.926734, 0.939718, 0.337226, -1.948, 13.2448)" width="14" x="1" y="7"/>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 931 B |
@@ -1,11 +0,0 @@
|
|||||||
<?xml version="1.0"?>
|
|
||||||
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid meet" version="1.1">
|
|
||||||
<!-- Created with SVG-edit - https://github.com/SVG-Edit/svgedit-->
|
|
||||||
|
|
||||||
<g class="layer">
|
|
||||||
<title>Layer 1</title>
|
|
||||||
<rect fill="#202020" height="2.25" id="svg_1" stroke="#202020" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" transform="matrix(1, 0, 0, 1, 0, 0)" width="13" x="1.5" y="4"/>
|
|
||||||
<rect fill="#202020" height="2.25" id="svg_2" stroke="#202020" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" transform="matrix(1, 0, 0, 1, 0, 0)" width="13" x="1.5" y="10"/>
|
|
||||||
<rect fill="#202020" height="1" id="svg_4" stroke="#202020" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" transform="matrix(0.341951, -0.926734, 0.939718, 0.337226, -1.948, 13.2448)" width="14" x="1" y="7"/>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 931 B |
@@ -119,7 +119,7 @@
|
|||||||
<string notr="true">ms</string>
|
<string notr="true">ms</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="minimum">
|
<property name="minimum">
|
||||||
<number>10</number>
|
<number>50</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="maximum">
|
<property name="maximum">
|
||||||
<number>20000</number>
|
<number>20000</number>
|
||||||
@@ -1275,22 +1275,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="toggleElseActions">
|
|
||||||
<property name="maximumSize">
|
|
||||||
<size>
|
|
||||||
<width>22</width>
|
|
||||||
<height>16777215</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="checkable">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="flat">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#include "advanced-scene-switcher.hpp"
|
#include "advanced-scene-switcher.hpp"
|
||||||
#include "switcher-data.hpp"
|
#include "switcher-data.hpp"
|
||||||
#include "macro-helpers.hpp"
|
|
||||||
#include "status-control.hpp"
|
#include "status-control.hpp"
|
||||||
#include "scene-switch-helpers.hpp"
|
#include "scene-switch-helpers.hpp"
|
||||||
#include "curl-helper.hpp"
|
#include "curl-helper.hpp"
|
||||||
@@ -11,7 +10,6 @@
|
|||||||
#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>
|
||||||
@@ -117,27 +115,10 @@ void AdvSceneSwitcher::LoadUI()
|
|||||||
loading = false;
|
loading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AdvSceneSwitcher::eventFilter(QObject *obj, QEvent *event)
|
|
||||||
{
|
|
||||||
auto eventType = event->type();
|
|
||||||
if (obj == ui->macroElseActions && eventType == QEvent::Resize) {
|
|
||||||
QResizeEvent *resizeEvent = static_cast<QResizeEvent *>(event);
|
|
||||||
|
|
||||||
if (resizeEvent->size().height() == 0) {
|
|
||||||
SetElseActionsStateToHidden();
|
|
||||||
return QDialog::eventFilter(obj, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
SetElseActionsStateToVisible();
|
|
||||||
}
|
|
||||||
|
|
||||||
return QDialog::eventFilter(obj, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Saving and loading
|
* Saving and loading
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
static void AskForBackup(const QString &json);
|
static void AskForBackup(obs_data_t *obj);
|
||||||
|
|
||||||
static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
|
static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
|
||||||
{
|
{
|
||||||
@@ -158,25 +139,16 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
|
|||||||
switcher->Stop();
|
switcher->Stop();
|
||||||
|
|
||||||
switcher->m.lock();
|
switcher->m.lock();
|
||||||
OBSDataAutoRelease obj =
|
obs_data_t *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)) {
|
||||||
auto json = obs_data_get_json(obj);
|
AskForBackup(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) {
|
||||||
@@ -185,12 +157,12 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void AskForBackup(const QString &json)
|
static void AskForBackup(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
const bool backupWasConfirmed = DisplayMessage(
|
bool backupSettings = DisplayMessage(
|
||||||
obs_module_text("AdvSceneSwitcher.askBackup"), true, false);
|
obs_module_text("AdvSceneSwitcher.askBackup"), true);
|
||||||
|
|
||||||
if (!backupWasConfirmed) {
|
if (!backupSettings) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,8 +181,8 @@ static void AskForBackup(const QString &json)
|
|||||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto out = QTextStream(&file);
|
|
||||||
out << json;
|
obs_data_save_json(obj, file.fileName().toUtf8().constData());
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
@@ -237,6 +209,7 @@ void SwitcherData::Thread()
|
|||||||
// if a longer transition is used than the configured check interval
|
// if a longer transition is used than the configured check interval
|
||||||
bool setPrevSceneAfterLinger = false;
|
bool setPrevSceneAfterLinger = false;
|
||||||
bool macroMatch = false;
|
bool macroMatch = false;
|
||||||
|
macroSceneSwitched = false;
|
||||||
endTime = std::chrono::high_resolution_clock::now();
|
endTime = std::chrono::high_resolution_clock::now();
|
||||||
auto runTime =
|
auto runTime =
|
||||||
std::chrono::duration_cast<std::chrono::milliseconds>(
|
std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||||
@@ -347,12 +320,22 @@ void SwitcherData::SetPreconditions()
|
|||||||
// Process name
|
// Process name
|
||||||
GetForegroundProcessName(currentForegroundProcess);
|
GetForegroundProcessName(currentForegroundProcess);
|
||||||
|
|
||||||
|
// Cursor
|
||||||
|
std::pair<int, int> cursorPos = GetCursorPos();
|
||||||
|
cursorPosChanged = cursorPos.first != switcher->lastCursorPos.first ||
|
||||||
|
cursorPos.second != switcher->lastCursorPos.second;
|
||||||
|
lastCursorPos = GetCursorPos();
|
||||||
|
|
||||||
// Macro
|
// Macro
|
||||||
InvalidateMacroTempVarValues();
|
InvalidateMacroTempVarValues();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClearWebsocketMessages();
|
||||||
|
|
||||||
void SwitcherData::ResetForNextInterval()
|
void SwitcherData::ResetForNextInterval()
|
||||||
{
|
{
|
||||||
|
// Core reset functions
|
||||||
|
ClearWebsocketMessages();
|
||||||
// Plugin reset functions
|
// Plugin reset functions
|
||||||
for (const auto &func : resetIntervalSteps) {
|
for (const auto &func : resetIntervalSteps) {
|
||||||
func();
|
func();
|
||||||
@@ -428,7 +411,7 @@ bool SwitcherData::CheckForMatch(OBSWeakSource &scene,
|
|||||||
|
|
||||||
static void ResetMacros()
|
static void ResetMacros()
|
||||||
{
|
{
|
||||||
for (auto &m : GetMacros()) {
|
for (auto &m : switcher->macros) {
|
||||||
m->ResetRunCount();
|
m->ResetRunCount();
|
||||||
m->ResetTimers();
|
m->ResetTimers();
|
||||||
}
|
}
|
||||||
@@ -471,9 +454,9 @@ void SwitcherData::Stop()
|
|||||||
if (th && th->isRunning()) {
|
if (th && th->isRunning()) {
|
||||||
stop = true;
|
stop = true;
|
||||||
cv.notify_all();
|
cv.notify_all();
|
||||||
SetMacroAbortWait(true);
|
abortMacroWait = true;
|
||||||
GetMacroWaitCV().notify_all();
|
macroWaitCv.notify_all();
|
||||||
GetMacroTransitionCV().notify_all();
|
macroTransitionCv.notify_all();
|
||||||
|
|
||||||
// Not waiting if a dialog was closed is a workaround to avoid
|
// Not waiting if a dialog was closed is a workaround to avoid
|
||||||
// deadlocks when a variable input dialog is opened while Stop()
|
// deadlocks when a variable input dialog is opened while Stop()
|
||||||
@@ -546,6 +529,9 @@ extern "C" void FreeSceneSwitcher()
|
|||||||
|
|
||||||
static void handleSceneChange()
|
static void handleSceneChange()
|
||||||
{
|
{
|
||||||
|
switcher->lastSceneChangeTime =
|
||||||
|
std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
// Stop waiting if scene was changed
|
// Stop waiting if scene was changed
|
||||||
if (switcher->SceneChangedDuringWait()) {
|
if (switcher->SceneChangedDuringWait()) {
|
||||||
switcher->cv.notify_one();
|
switcher->cv.notify_one();
|
||||||
@@ -612,9 +598,28 @@ static void handlePeviewSceneChange()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handleTransitionEnd()
|
static void setReplayBufferSaved()
|
||||||
{
|
{
|
||||||
GetMacroTransitionCV().notify_all();
|
switcher->replayBufferSaved = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setTranstionEnd()
|
||||||
|
{
|
||||||
|
switcher->lastTransitionEndTime =
|
||||||
|
std::chrono::high_resolution_clock::now();
|
||||||
|
switcher->macroTransitionCv.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setStreamStarting()
|
||||||
|
{
|
||||||
|
switcher->lastStreamStartingTime =
|
||||||
|
std::chrono::high_resolution_clock::now();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setStreamStopping()
|
||||||
|
{
|
||||||
|
switcher->lastStreamStoppingTime =
|
||||||
|
std::chrono::high_resolution_clock::now();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handleShutdown()
|
static void handleShutdown()
|
||||||
@@ -623,10 +628,10 @@ static void handleShutdown()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switcher->obsIsShuttingDown = true;
|
switcher->obsIsShuttingDown = true;
|
||||||
if (ShutdownCheckIsNecessary()) {
|
if (switcher->shutdownConditionCount) {
|
||||||
switcher->Stop();
|
switcher->Stop();
|
||||||
CheckMacros();
|
switcher->CheckMacros();
|
||||||
RunMacros();
|
switcher->RunMacros();
|
||||||
|
|
||||||
// Unfortunately this will not work as OBS will now allow saving
|
// Unfortunately this will not work as OBS will now allow saving
|
||||||
// the scene collection data at this point, So any OBS specific
|
// the scene collection data at this point, So any OBS specific
|
||||||
@@ -683,8 +688,19 @@ static void OBSEvent(enum obs_frontend_event event, void *switcher)
|
|||||||
case OBS_FRONTEND_EVENT_STREAMING_STOPPED:
|
case OBS_FRONTEND_EVENT_STREAMING_STOPPED:
|
||||||
resetLiveTime();
|
resetLiveTime();
|
||||||
break;
|
break;
|
||||||
|
#if LIBOBS_API_VER >= MAKE_SEMANTIC_VERSION(26, 0, 0)
|
||||||
|
case OBS_FRONTEND_EVENT_REPLAY_BUFFER_SAVED:
|
||||||
|
setReplayBufferSaved();
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
case OBS_FRONTEND_EVENT_TRANSITION_STOPPED:
|
case OBS_FRONTEND_EVENT_TRANSITION_STOPPED:
|
||||||
handleTransitionEnd();
|
setTranstionEnd();
|
||||||
|
break;
|
||||||
|
case OBS_FRONTEND_EVENT_STREAMING_STARTING:
|
||||||
|
setStreamStarting();
|
||||||
|
break;
|
||||||
|
case OBS_FRONTEND_EVENT_STREAMING_STOPPING:
|
||||||
|
setStreamStopping();
|
||||||
break;
|
break;
|
||||||
#if LIBOBS_API_VER >= MAKE_SEMANTIC_VERSION(27, 2, 0)
|
#if LIBOBS_API_VER >= MAKE_SEMANTIC_VERSION(27, 2, 0)
|
||||||
case OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGING:
|
case OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGING:
|
||||||
@@ -743,9 +759,6 @@ void OpenSettingsWindow()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetupConnectionManager();
|
|
||||||
void SetupWebsocketHelpers();
|
|
||||||
|
|
||||||
extern "C" void InitSceneSwitcher(obs_module_t *module, translateFunc translate)
|
extern "C" void InitSceneSwitcher(obs_module_t *module, translateFunc translate)
|
||||||
{
|
{
|
||||||
blog(LOG_INFO, "version: %s", g_GIT_TAG);
|
blog(LOG_INFO, "version: %s", g_GIT_TAG);
|
||||||
@@ -756,8 +769,6 @@ extern "C" void InitSceneSwitcher(obs_module_t *module, translateFunc translate)
|
|||||||
PlatformInit();
|
PlatformInit();
|
||||||
LoadPlugins();
|
LoadPlugins();
|
||||||
SetupDock();
|
SetupDock();
|
||||||
SetupConnectionManager();
|
|
||||||
SetupWebsocketHelpers();
|
|
||||||
|
|
||||||
obs_frontend_add_save_callback(SaveSceneSwitcher, nullptr);
|
obs_frontend_add_save_callback(SaveSceneSwitcher, nullptr);
|
||||||
obs_frontend_add_event_callback(OBSEvent, switcher);
|
obs_frontend_add_event_callback(OBSEvent, switcher);
|
||||||
|
|||||||
@@ -39,9 +39,6 @@ public:
|
|||||||
void RestoreWindowGeo();
|
void RestoreWindowGeo();
|
||||||
void CheckFirstTimeSetup();
|
void CheckFirstTimeSetup();
|
||||||
|
|
||||||
protected:
|
|
||||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
|
||||||
|
|
||||||
/* --- Begin of general tab section --- */
|
/* --- Begin of general tab section --- */
|
||||||
public:
|
public:
|
||||||
void SetupGeneralTab();
|
void SetupGeneralTab();
|
||||||
@@ -118,7 +115,6 @@ public slots:
|
|||||||
void on_actionUp_clicked();
|
void on_actionUp_clicked();
|
||||||
void on_actionDown_clicked();
|
void on_actionDown_clicked();
|
||||||
void on_actionBottom_clicked();
|
void on_actionBottom_clicked();
|
||||||
void on_toggleElseActions_clicked();
|
|
||||||
void on_elseActionAdd_clicked();
|
void on_elseActionAdd_clicked();
|
||||||
void on_elseActionRemove_clicked();
|
void on_elseActionRemove_clicked();
|
||||||
void on_elseActionTop_clicked();
|
void on_elseActionTop_clicked();
|
||||||
@@ -150,8 +146,6 @@ public slots:
|
|||||||
void MaximizeElseActions();
|
void MaximizeElseActions();
|
||||||
void MinimizeConditions();
|
void MinimizeConditions();
|
||||||
void MaximizeConditions();
|
void MaximizeConditions();
|
||||||
void SetElseActionsStateToHidden();
|
|
||||||
void SetElseActionsStateToVisible();
|
|
||||||
void MacroActionSelectionChanged(int idx);
|
void MacroActionSelectionChanged(int idx);
|
||||||
void MacroActionReorder(int to, int target);
|
void MacroActionReorder(int to, int target);
|
||||||
void AddMacroAction(int idx);
|
void AddMacroAction(int idx);
|
||||||
@@ -340,7 +334,7 @@ public slots:
|
|||||||
void on_timeUp_clicked();
|
void on_timeUp_clicked();
|
||||||
void on_timeDown_clicked();
|
void on_timeDown_clicked();
|
||||||
|
|
||||||
// Audio tab
|
// Video tab
|
||||||
public:
|
public:
|
||||||
void SetupAudioTab();
|
void SetupAudioTab();
|
||||||
public slots:
|
public slots:
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
#include "status-control.hpp"
|
#include "status-control.hpp"
|
||||||
#include "file-selection.hpp"
|
#include "file-selection.hpp"
|
||||||
#include "filter-combo-box.hpp"
|
#include "filter-combo-box.hpp"
|
||||||
#include "variable.hpp"
|
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
@@ -34,7 +33,7 @@ void AdvSceneSwitcher::on_noMatchDontSwitch_clicked()
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switcher->switchIfNotMatching = NoMatchBehavior::NO_SWITCH;
|
switcher->switchIfNotMatching = SwitcherData::NoMatch::NO_SWITCH;
|
||||||
ui->noMatchSwitchScene->setEnabled(false);
|
ui->noMatchSwitchScene->setEnabled(false);
|
||||||
ui->randomDisabledWarning->setVisible(true);
|
ui->randomDisabledWarning->setVisible(true);
|
||||||
}
|
}
|
||||||
@@ -46,7 +45,7 @@ void AdvSceneSwitcher::on_noMatchSwitch_clicked()
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switcher->switchIfNotMatching = NoMatchBehavior::SWITCH;
|
switcher->switchIfNotMatching = SwitcherData::NoMatch::SWITCH;
|
||||||
ui->noMatchSwitchScene->setEnabled(true);
|
ui->noMatchSwitchScene->setEnabled(true);
|
||||||
UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText());
|
UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText());
|
||||||
ui->randomDisabledWarning->setVisible(true);
|
ui->randomDisabledWarning->setVisible(true);
|
||||||
@@ -59,7 +58,7 @@ void AdvSceneSwitcher::on_noMatchRandomSwitch_clicked()
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switcher->switchIfNotMatching = NoMatchBehavior::RANDOM_SWITCH;
|
switcher->switchIfNotMatching = SwitcherData::NoMatch::RANDOM_SWITCH;
|
||||||
ui->noMatchSwitchScene->setEnabled(false);
|
ui->noMatchSwitchScene->setEnabled(false);
|
||||||
ui->randomDisabledWarning->setVisible(false);
|
ui->randomDisabledWarning->setVisible(false);
|
||||||
}
|
}
|
||||||
@@ -507,13 +506,13 @@ void SwitcherData::LoadSettings(obs_data_t *obj)
|
|||||||
// selections to be available.
|
// selections to be available.
|
||||||
loadSceneGroups(obj);
|
loadSceneGroups(obj);
|
||||||
LoadVariables(obj);
|
LoadVariables(obj);
|
||||||
|
LoadConnections(obj);
|
||||||
|
|
||||||
for (const auto &func : loadSteps) {
|
for (const auto &func : loadSteps) {
|
||||||
func(obj);
|
func(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadMacros(obj);
|
LoadMacros(obj);
|
||||||
LoadGlobalMacroProperties(obj);
|
|
||||||
loadWindowTitleSwitches(obj);
|
loadWindowTitleSwitches(obj);
|
||||||
loadScreenRegionSwitches(obj);
|
loadScreenRegionSwitches(obj);
|
||||||
loadPauseSwitches(obj);
|
loadPauseSwitches(obj);
|
||||||
@@ -550,7 +549,7 @@ void SwitcherData::SaveSettings(obs_data_t *obj)
|
|||||||
|
|
||||||
saveSceneGroups(obj);
|
saveSceneGroups(obj);
|
||||||
SaveMacros(obj);
|
SaveMacros(obj);
|
||||||
SaveGlobalMacroProperties(obj);
|
SaveConnections(obj);
|
||||||
SaveVariables(obj);
|
SaveVariables(obj);
|
||||||
saveWindowTitleSwitches(obj);
|
saveWindowTitleSwitches(obj);
|
||||||
saveScreenRegionSwitches(obj);
|
saveScreenRegionSwitches(obj);
|
||||||
@@ -625,9 +624,9 @@ void SwitcherData::LoadGeneralSettings(obs_data_t *obj)
|
|||||||
interval = obs_data_get_int(obj, "interval");
|
interval = obs_data_get_int(obj, "interval");
|
||||||
|
|
||||||
obs_data_set_default_int(obj, "switch_if_not_matching",
|
obs_data_set_default_int(obj, "switch_if_not_matching",
|
||||||
static_cast<int>(NoMatchBehavior::NO_SWITCH));
|
static_cast<int>(NoMatch::NO_SWITCH));
|
||||||
switchIfNotMatching = static_cast<NoMatchBehavior>(
|
switchIfNotMatching =
|
||||||
obs_data_get_int(obj, "switch_if_not_matching"));
|
(NoMatch)obs_data_get_int(obj, "switch_if_not_matching");
|
||||||
std::string nonMatchingSceneName =
|
std::string nonMatchingSceneName =
|
||||||
obs_data_get_string(obj, "non_matching_scene");
|
obs_data_get_string(obj, "non_matching_scene");
|
||||||
nonMatchingScene = GetWeakSourceByName(nonMatchingSceneName.c_str());
|
nonMatchingScene = GetWeakSourceByName(nonMatchingSceneName.c_str());
|
||||||
@@ -801,13 +800,12 @@ void SwitcherData::CheckNoMatchSwitch(bool &match, OBSWeakSource &scene,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (switchIfNotMatching == NoMatchBehavior::SWITCH &&
|
if (switchIfNotMatching == NoMatch::SWITCH && nonMatchingScene) {
|
||||||
nonMatchingScene) {
|
|
||||||
match = true;
|
match = true;
|
||||||
scene = nonMatchingScene;
|
scene = nonMatchingScene;
|
||||||
transition = nullptr;
|
transition = nullptr;
|
||||||
}
|
}
|
||||||
if (switchIfNotMatching == NoMatchBehavior::RANDOM_SWITCH) {
|
if (switchIfNotMatching == NoMatch::RANDOM_SWITCH) {
|
||||||
match = checkRandom(scene, transition, sleep);
|
match = checkRandom(scene, transition, sleep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -958,11 +956,11 @@ void AdvSceneSwitcher::SetupGeneralTab()
|
|||||||
{
|
{
|
||||||
PopulateSceneSelection(ui->noMatchSwitchScene, false);
|
PopulateSceneSelection(ui->noMatchSwitchScene, false);
|
||||||
|
|
||||||
if (switcher->switchIfNotMatching == NoMatchBehavior::SWITCH) {
|
if (switcher->switchIfNotMatching == SwitcherData::NoMatch::SWITCH) {
|
||||||
ui->noMatchSwitch->setChecked(true);
|
ui->noMatchSwitch->setChecked(true);
|
||||||
ui->noMatchSwitchScene->setEnabled(true);
|
ui->noMatchSwitchScene->setEnabled(true);
|
||||||
} else if (switcher->switchIfNotMatching ==
|
} else if (switcher->switchIfNotMatching ==
|
||||||
NoMatchBehavior::NO_SWITCH) {
|
SwitcherData::NoMatch::NO_SWITCH) {
|
||||||
ui->noMatchDontSwitch->setChecked(true);
|
ui->noMatchDontSwitch->setChecked(true);
|
||||||
ui->noMatchSwitchScene->setEnabled(false);
|
ui->noMatchSwitchScene->setEnabled(false);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -160,9 +160,7 @@ enum class HotkeyType {
|
|||||||
Key_NumpadMultiply,
|
Key_NumpadMultiply,
|
||||||
Key_NumpadDivide,
|
Key_NumpadDivide,
|
||||||
Key_NumpadDecimal,
|
Key_NumpadDecimal,
|
||||||
Key_NumpadEnter,
|
Key_NumpadEnter
|
||||||
|
|
||||||
Key_Tilde,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -12,11 +12,6 @@ namespace advss {
|
|||||||
static QMetaObject::Connection addPulse;
|
static QMetaObject::Connection addPulse;
|
||||||
SceneGroupEditWidget *typeEdit = nullptr;
|
SceneGroupEditWidget *typeEdit = nullptr;
|
||||||
|
|
||||||
std::deque<SceneGroup> &GetSceneGroups()
|
|
||||||
{
|
|
||||||
return switcher->sceneGroups;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneGroup::advanceIdx()
|
void SceneGroup::advanceIdx()
|
||||||
{
|
{
|
||||||
currentIdx++;
|
currentIdx++;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <deque>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
@@ -87,6 +87,5 @@ private:
|
|||||||
|
|
||||||
SceneGroup *GetSceneGroupByName(const char *name);
|
SceneGroup *GetSceneGroupByName(const char *name);
|
||||||
SceneGroup *GetSceneGroupByQString(const QString &name);
|
SceneGroup *GetSceneGroupByQString(const QString &name);
|
||||||
std::deque<SceneGroup> &GetSceneGroups();
|
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -177,17 +177,17 @@ static std::string getRemoteData(std::string &url)
|
|||||||
{
|
{
|
||||||
std::string readBuffer;
|
std::string readBuffer;
|
||||||
|
|
||||||
CurlHelper::SetOpt(CURLOPT_URL, url.c_str());
|
switcher->curl.SetOpt(CURLOPT_URL, url.c_str());
|
||||||
CurlHelper::SetOpt(CURLOPT_WRITEFUNCTION, WriteCallback);
|
switcher->curl.SetOpt(CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||||
CurlHelper::SetOpt(CURLOPT_WRITEDATA, &readBuffer);
|
switcher->curl.SetOpt(CURLOPT_WRITEDATA, &readBuffer);
|
||||||
|
|
||||||
// Set timeout to at least one second
|
// Set timeout to at least one second
|
||||||
int timeout = switcher->interval / 1000;
|
int timeout = switcher->interval / 1000;
|
||||||
if (timeout == 0) {
|
if (timeout == 0) {
|
||||||
timeout = 1;
|
timeout = 1;
|
||||||
}
|
}
|
||||||
CurlHelper::SetOpt(CURLOPT_TIMEOUT, 1);
|
switcher->curl.SetOpt(CURLOPT_TIMEOUT, 1);
|
||||||
CurlHelper::Perform();
|
switcher->curl.Perform();
|
||||||
|
|
||||||
return readBuffer;
|
return readBuffer;
|
||||||
}
|
}
|
||||||
@@ -422,7 +422,7 @@ void AdvSceneSwitcher::SetupFileTab()
|
|||||||
obs_module_text("AdvSceneSwitcher.fileTab.remoteFileWarning2"));
|
obs_module_text("AdvSceneSwitcher.fileTab.remoteFileWarning2"));
|
||||||
ui->remoteFileWarningLabel->hide();
|
ui->remoteFileWarningLabel->hide();
|
||||||
|
|
||||||
if (CurlHelper::Initialized()) {
|
if (switcher->curl.Initialized()) {
|
||||||
ui->libcurlWarning->setVisible(false);
|
ui->libcurlWarning->setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -143,7 +143,8 @@ void AdvSceneSwitcher::SetupRandomTab()
|
|||||||
border-radius: 7px; \
|
border-radius: 7px; \
|
||||||
border-color: rgb(0,0,0,0) \
|
border-color: rgb(0,0,0,0) \
|
||||||
}");
|
}");
|
||||||
if (switcher->switchIfNotMatching != NoMatchBehavior::RANDOM_SWITCH) {
|
if (switcher->switchIfNotMatching !=
|
||||||
|
SwitcherData::NoMatch::RANDOM_SWITCH) {
|
||||||
if (!switcher->disableHints) {
|
if (!switcher->disableHints) {
|
||||||
PulseWidget(ui->randomDisabledWarning, QColor(Qt::red),
|
PulseWidget(ui->randomDisabledWarning, QColor(Qt::red),
|
||||||
QColor(0, 0, 0, 0));
|
QColor(0, 0, 0, 0));
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#include "platform-funcs.hpp"
|
#include "platform-funcs.hpp"
|
||||||
#include "hotkey.hpp"
|
#include "hotkey.hpp"
|
||||||
#include "log-helper.hpp"
|
|
||||||
|
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/Xatom.h>
|
#include <X11/Xatom.h>
|
||||||
@@ -26,10 +25,9 @@
|
|||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QLibrary>
|
#include <QLibrary>
|
||||||
#ifdef PROCPS_AVAILABLE
|
#ifdef USE_PROCPS
|
||||||
#include <proc/readproc.h>
|
#include <proc/readproc.h>
|
||||||
#endif
|
#else
|
||||||
#ifdef PROCPS2_AVAILABLE
|
|
||||||
#include <libproc2/pids.h>
|
#include <libproc2/pids.h>
|
||||||
#endif
|
#endif
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@@ -55,31 +53,6 @@ std::chrono::high_resolution_clock::time_point lastMouseLeftClickTime{};
|
|||||||
std::chrono::high_resolution_clock::time_point lastMouseMiddleClickTime{};
|
std::chrono::high_resolution_clock::time_point lastMouseMiddleClickTime{};
|
||||||
std::chrono::high_resolution_clock::time_point lastMouseRightClickTime{};
|
std::chrono::high_resolution_clock::time_point lastMouseRightClickTime{};
|
||||||
|
|
||||||
static QLibrary *libprocps = nullptr;
|
|
||||||
#ifdef PROCPS_AVAILABLE
|
|
||||||
typedef PROCTAB *(*openproc_func)(int flags);
|
|
||||||
typedef void (*closeproc_func)(PROCTAB *PT);
|
|
||||||
typedef proc_t *(*readproc_func)(PROCTAB *__restrict const PT,
|
|
||||||
proc_t *__restrict p);
|
|
||||||
static openproc_func openproc_ = nullptr;
|
|
||||||
static closeproc_func closeproc_ = nullptr;
|
|
||||||
static readproc_func readproc_ = nullptr;
|
|
||||||
#endif
|
|
||||||
static bool libprocpsSupported = false;
|
|
||||||
|
|
||||||
static QLibrary *libproc2 = nullptr;
|
|
||||||
#ifdef PROCPS2_AVAILABLE
|
|
||||||
typedef int (*procps_pids_new_func)(struct pids_info **info,
|
|
||||||
enum pids_item *items, int numitems);
|
|
||||||
typedef struct pids_stack *(*procps_pids_get_func)(struct pids_info *info,
|
|
||||||
enum pids_fetch_type which);
|
|
||||||
typedef int (*procps_pids_unref_func)(struct pids_info **info);
|
|
||||||
static procps_pids_new_func procps_pids_new_ = nullptr;
|
|
||||||
static procps_pids_get_func procps_pids_get_ = nullptr;
|
|
||||||
static procps_pids_unref_func procps_pids_unref_ = nullptr;
|
|
||||||
#endif
|
|
||||||
static bool libprocps2Supported = false;
|
|
||||||
|
|
||||||
Display *disp()
|
Display *disp()
|
||||||
{
|
{
|
||||||
if (!xdisplay) {
|
if (!xdisplay) {
|
||||||
@@ -365,57 +338,46 @@ std::optional<std::string> GetTextInWindow(const std::string &)
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
static void getProcessListProcps(QStringList &processes)
|
#ifdef USE_PROCPS
|
||||||
|
void GetProcessList(QStringList &processes)
|
||||||
{
|
{
|
||||||
#ifdef PROCPS_AVAILABLE
|
processes.clear();
|
||||||
PROCTAB *proc = openproc_(PROC_FILLSTAT);
|
PROCTAB *proc = openproc(PROC_FILLSTAT);
|
||||||
proc_t proc_info;
|
proc_t proc_info;
|
||||||
memset(&proc_info, 0, sizeof(proc_info));
|
memset(&proc_info, 0, sizeof(proc_info));
|
||||||
while (readproc_(proc, &proc_info) != NULL) {
|
while (readproc(proc, &proc_info) != NULL) {
|
||||||
QString procName(proc_info.cmd);
|
QString procName(proc_info.cmd);
|
||||||
if (!procName.isEmpty() && !processes.contains(procName)) {
|
if (!procName.isEmpty() && !processes.contains(procName)) {
|
||||||
processes << procName;
|
processes << procName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
closeproc_(proc);
|
closeproc(proc);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
static void getProcessListProcps2(QStringList &processes)
|
void GetProcessList(QStringList &processes)
|
||||||
{
|
{
|
||||||
#ifdef PROCPS2_AVAILABLE
|
processes.clear();
|
||||||
struct pids_info *info = NULL;
|
struct pids_info *info = NULL;
|
||||||
struct pids_stack *stack;
|
struct pids_stack *stack;
|
||||||
enum pids_item Items[] = {
|
enum pids_item Items[] = {
|
||||||
PIDS_CMD,
|
PIDS_CMD,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (procps_pids_new_(&info, Items, sizeof(Items) / sizeof(Items[0])) <
|
if (procps_pids_new(&info, Items, sizeof(Items) / sizeof(Items[0])) <
|
||||||
0) {
|
0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
while ((stack = procps_pids_get_(info, PIDS_FETCH_TASKS_ONLY))) {
|
|
||||||
|
while ((stack = procps_pids_get(info, PIDS_FETCH_TASKS_ONLY))) {
|
||||||
auto cmd = PIDS_VAL(0, str, stack, info);
|
auto cmd = PIDS_VAL(0, str, stack, info);
|
||||||
QString procName(cmd);
|
QString procName(cmd);
|
||||||
if (!procName.isEmpty() && !processes.contains(procName)) {
|
if (!procName.isEmpty() && !processes.contains(procName)) {
|
||||||
processes << procName;
|
processes << procName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
procps_pids_unref_(&info);
|
procps_pids_unref(&info);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
void GetProcessList(QStringList &processes)
|
|
||||||
{
|
|
||||||
processes.clear();
|
|
||||||
if (libprocpsSupported) {
|
|
||||||
getProcessListProcps(processes);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (libprocps2Supported) {
|
|
||||||
getProcessListProcps2(processes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
long getForegroundProcessPid()
|
long getForegroundProcessPid()
|
||||||
{
|
{
|
||||||
@@ -555,9 +517,6 @@ static std::unordered_map<HotkeyType, long> keyTable = {
|
|||||||
{HotkeyType::Key_8, XK_8},
|
{HotkeyType::Key_8, XK_8},
|
||||||
{HotkeyType::Key_9, XK_9},
|
{HotkeyType::Key_9, XK_9},
|
||||||
|
|
||||||
// Other
|
|
||||||
{HotkeyType::Key_Tilde, XK_asciitilde},
|
|
||||||
|
|
||||||
{HotkeyType::Key_F1, XK_F1},
|
{HotkeyType::Key_F1, XK_F1},
|
||||||
{HotkeyType::Key_F2, XK_F2},
|
{HotkeyType::Key_F2, XK_F2},
|
||||||
{HotkeyType::Key_F3, XK_F3},
|
{HotkeyType::Key_F3, XK_F3},
|
||||||
@@ -674,58 +633,6 @@ void PressKeys(const std::vector<HotkeyType> keys, int duration)
|
|||||||
XFlush(display);
|
XFlush(display);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void initXtst()
|
|
||||||
{
|
|
||||||
libXtstHandle = new QLibrary("libXtst", nullptr);
|
|
||||||
pressFunc = (keyPressFunc)libXtstHandle->resolve("XTestFakeKeyEvent");
|
|
||||||
int _;
|
|
||||||
canSimulateKeyPresses = pressFunc &&
|
|
||||||
XQueryExtension(disp(), "XTEST", &_, &_, &_);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void initXss()
|
|
||||||
{
|
|
||||||
libXssHandle = new QLibrary("libXss", nullptr);
|
|
||||||
allocSSFunc = (XScreenSaverAllocInfoFunc)libXssHandle->resolve(
|
|
||||||
"XScreenSaverAllocInfo");
|
|
||||||
querySSFunc = (XScreenSaverQueryInfoFunc)libXssHandle->resolve(
|
|
||||||
"XScreenSaverQueryInfo");
|
|
||||||
int _;
|
|
||||||
canGetIdleTime = allocSSFunc && querySSFunc &&
|
|
||||||
XQueryExtension(disp(), ScreenSaverName, &_, &_, &_);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void initProcps()
|
|
||||||
{
|
|
||||||
#ifdef PROCPS_AVAILABLE
|
|
||||||
libprocps = new QLibrary("libprocps", nullptr);
|
|
||||||
openproc_ = (openproc_func)libprocps->resolve("openproc");
|
|
||||||
closeproc_ = (closeproc_func)libprocps->resolve("closeproc");
|
|
||||||
readproc_ = (readproc_func)libprocps->resolve("readproc");
|
|
||||||
if (openproc_ && closeproc_ && readproc_) {
|
|
||||||
libprocpsSupported = true;
|
|
||||||
blog(LOG_INFO, "libprocps symbols resolved successfully!");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void initProc2()
|
|
||||||
{
|
|
||||||
#ifdef PROCPS2_AVAILABLE
|
|
||||||
libproc2 = new QLibrary("libproc2", nullptr);
|
|
||||||
procps_pids_new_ =
|
|
||||||
(procps_pids_new_func)libproc2->resolve("procps_pids_new");
|
|
||||||
procps_pids_get_ =
|
|
||||||
(procps_pids_get_func)libproc2->resolve("procps_pids_get");
|
|
||||||
procps_pids_unref_ =
|
|
||||||
(procps_pids_unref_func)libproc2->resolve("procps_pids_unref");
|
|
||||||
if (procps_pids_new_ && procps_pids_get_ && procps_pids_unref_) {
|
|
||||||
libprocps2Supported = true;
|
|
||||||
blog(LOG_INFO, "libproc2 symbols resolved successfully!");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlatformInit()
|
void PlatformInit()
|
||||||
{
|
{
|
||||||
auto display = disp();
|
auto display = disp();
|
||||||
@@ -733,26 +640,31 @@ void PlatformInit()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
initXtst();
|
libXtstHandle = new QLibrary("libXtst", nullptr);
|
||||||
initXss();
|
pressFunc = (keyPressFunc)libXtstHandle->resolve("XTestFakeKeyEvent");
|
||||||
initProcps();
|
int _;
|
||||||
initProc2();
|
canSimulateKeyPresses = pressFunc &&
|
||||||
}
|
XQueryExtension(disp(), "XTEST", &_, &_, &_);
|
||||||
|
|
||||||
static void cleanupHelper(QLibrary *lib)
|
libXssHandle = new QLibrary("libXss", nullptr);
|
||||||
{
|
allocSSFunc = (XScreenSaverAllocInfoFunc)libXssHandle->resolve(
|
||||||
if (lib) {
|
"XScreenSaverAllocInfo");
|
||||||
delete lib;
|
querySSFunc = (XScreenSaverQueryInfoFunc)libXssHandle->resolve(
|
||||||
lib = nullptr;
|
"XScreenSaverQueryInfo");
|
||||||
}
|
canGetIdleTime = allocSSFunc && querySSFunc &&
|
||||||
|
XQueryExtension(disp(), ScreenSaverName, &_, &_, &_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlatformCleanup()
|
void PlatformCleanup()
|
||||||
{
|
{
|
||||||
cleanupHelper(libXtstHandle);
|
if (libXtstHandle) {
|
||||||
cleanupHelper(libXssHandle);
|
delete libXtstHandle;
|
||||||
cleanupHelper(libprocps);
|
libXtstHandle = nullptr;
|
||||||
cleanupHelper(libproc2);
|
}
|
||||||
|
if (libXssHandle) {
|
||||||
|
delete libXssHandle;
|
||||||
|
libXssHandle = nullptr;
|
||||||
|
}
|
||||||
cleanupDisplay();
|
cleanupDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "macro-action-audio.hpp"
|
#include "macro-action-audio.hpp"
|
||||||
#include "macro.hpp"
|
#include "switcher-data.hpp"
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
@@ -36,16 +36,6 @@ const static std::map<MacroActionAudio::FadeType, std::string> fadeTypes = {
|
|||||||
"AdvSceneSwitcher.action.audio.fade.type.rate"},
|
"AdvSceneSwitcher.action.audio.fade.type.rate"},
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace {
|
|
||||||
struct FadeInfo {
|
|
||||||
std::atomic_bool active = {false};
|
|
||||||
std::atomic_int id = {0};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static FadeInfo masterAudioFade;
|
|
||||||
static std::unordered_map<std::string, FadeInfo> audioFades;
|
|
||||||
|
|
||||||
constexpr auto fadeInterval = std::chrono::milliseconds(100);
|
constexpr auto fadeInterval = std::chrono::milliseconds(100);
|
||||||
constexpr float minFade = 0.000001f;
|
constexpr float minFade = 0.000001f;
|
||||||
|
|
||||||
@@ -68,9 +58,10 @@ auto set_master_volume = obs_set_master_volume;
|
|||||||
void MacroActionAudio::SetFadeActive(bool value)
|
void MacroActionAudio::SetFadeActive(bool value)
|
||||||
{
|
{
|
||||||
if (_action == Action::SOURCE_VOLUME) {
|
if (_action == Action::SOURCE_VOLUME) {
|
||||||
audioFades[_audioSource.ToString()].active = value;
|
switcher->activeAudioFades[_audioSource.ToString()].active =
|
||||||
|
value;
|
||||||
} else {
|
} else {
|
||||||
masterAudioFade.active = value;
|
switcher->masterAudioFade.active = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,13 +69,14 @@ bool MacroActionAudio::FadeActive()
|
|||||||
{
|
{
|
||||||
bool active = true;
|
bool active = true;
|
||||||
if (_action == Action::SOURCE_VOLUME) {
|
if (_action == Action::SOURCE_VOLUME) {
|
||||||
auto it = audioFades.find(_audioSource.ToString());
|
auto it = switcher->activeAudioFades.find(
|
||||||
if (it == audioFades.end()) {
|
_audioSource.ToString());
|
||||||
|
if (it == switcher->activeAudioFades.end()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
active = it->second.active;
|
active = it->second.active;
|
||||||
} else {
|
} else {
|
||||||
active = masterAudioFade.active;
|
active = switcher->masterAudioFade.active;
|
||||||
}
|
}
|
||||||
|
|
||||||
return active;
|
return active;
|
||||||
@@ -94,13 +86,14 @@ std::atomic_int *MacroActionAudio::GetFadeIdPtr()
|
|||||||
{
|
{
|
||||||
|
|
||||||
if (_action == Action::SOURCE_VOLUME) {
|
if (_action == Action::SOURCE_VOLUME) {
|
||||||
auto it = audioFades.find(_audioSource.ToString());
|
auto it = switcher->activeAudioFades.find(
|
||||||
if (it == audioFades.end()) {
|
_audioSource.ToString());
|
||||||
|
if (it == switcher->activeAudioFades.end()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return &it->second.id;
|
return &it->second.id;
|
||||||
}
|
}
|
||||||
return &masterAudioFade.id;
|
return &switcher->masterAudioFade.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroActionAudio::SetVolume(float vol)
|
void MacroActionAudio::SetVolume(float vol)
|
||||||
|
|||||||
@@ -1,256 +0,0 @@
|
|||||||
#include "macro-action-clipboard.hpp"
|
|
||||||
#include "curl-helper.hpp"
|
|
||||||
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QClipboard>
|
|
||||||
#include <QImage>
|
|
||||||
#include <QMimeData>
|
|
||||||
|
|
||||||
namespace advss {
|
|
||||||
|
|
||||||
const std::string MacroActionClipboard::id = "clipboard";
|
|
||||||
|
|
||||||
bool MacroActionClipboard::_registered = MacroActionFactory::Register(
|
|
||||||
MacroActionClipboard::id,
|
|
||||||
{MacroActionClipboard::Create, MacroActionClipboardEdit::Create,
|
|
||||||
"AdvSceneSwitcher.action.clipboard"});
|
|
||||||
|
|
||||||
const static std::map<MacroActionClipboard::Action, std::string> actionTypes = {
|
|
||||||
{MacroActionClipboard::Action::COPY_TEXT,
|
|
||||||
"AdvSceneSwitcher.action.clipboard.type.copy.text"},
|
|
||||||
{MacroActionClipboard::Action::COPY_IMAGE,
|
|
||||||
"AdvSceneSwitcher.action.clipboard.type.copy.image"},
|
|
||||||
};
|
|
||||||
|
|
||||||
static size_t writeCallback(void *ptr, size_t size, size_t nmemb,
|
|
||||||
QByteArray *buffer)
|
|
||||||
{
|
|
||||||
buffer->append((char *)ptr, nmemb);
|
|
||||||
return size * nmemb;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::optional<QImage> getImageFromUrl(const char *url)
|
|
||||||
{
|
|
||||||
QByteArray response;
|
|
||||||
|
|
||||||
CurlHelper::SetOpt(CURLOPT_URL, url);
|
|
||||||
CurlHelper::SetOpt(CURLOPT_HTTPGET, 1L);
|
|
||||||
CurlHelper::SetOpt(CURLOPT_TIMEOUT_MS, 30000);
|
|
||||||
CurlHelper::SetOpt(CURLOPT_WRITEFUNCTION, writeCallback);
|
|
||||||
CurlHelper::SetOpt(CURLOPT_WRITEDATA, &response);
|
|
||||||
auto code = CurlHelper::Perform();
|
|
||||||
|
|
||||||
if (code != CURLE_OK) {
|
|
||||||
blog(LOG_WARNING,
|
|
||||||
"Retrieving image failed in %s with error: %s", __func__,
|
|
||||||
CurlHelper::GetError(code));
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
return QImage::fromData(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setMimeTypeParams(ClipboardQueueParams *params,
|
|
||||||
QClipboard *clipboard)
|
|
||||||
{
|
|
||||||
auto mimeData = clipboard->mimeData();
|
|
||||||
if (!mimeData) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto mimeTypeList = mimeData->formats();
|
|
||||||
if (mimeTypeList.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
params->mimeTypePrimary = mimeTypeList.first().toStdString();
|
|
||||||
params->mimeTypeAll = mimeTypeList.join(" ").toStdString();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void copyText(void *param)
|
|
||||||
{
|
|
||||||
auto params = static_cast<ClipboardTextQueueParams *>(param);
|
|
||||||
QClipboard *clipboard = QApplication::clipboard();
|
|
||||||
|
|
||||||
clipboard->setText(params->text.c_str());
|
|
||||||
|
|
||||||
setMimeTypeParams(params, clipboard);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void copyImageFromUrl(void *param)
|
|
||||||
{
|
|
||||||
auto params = static_cast<ClipboardImageQueueParams *>(param);
|
|
||||||
auto url = params->url.c_str();
|
|
||||||
auto image = getImageFromUrl(url);
|
|
||||||
|
|
||||||
if (!image || (*image).isNull()) {
|
|
||||||
blog(LOG_WARNING, "Failed to convert %s URL to image!", url);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QClipboard *clipboard = QApplication::clipboard();
|
|
||||||
clipboard->setImage(*image);
|
|
||||||
|
|
||||||
setMimeTypeParams(params, clipboard);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MacroActionClipboard::PerformAction()
|
|
||||||
{
|
|
||||||
switch (_action) {
|
|
||||||
case Action::COPY_TEXT: {
|
|
||||||
ClipboardTextQueueParams params{"", "", _text};
|
|
||||||
obs_queue_task(OBS_TASK_UI, copyText, ¶ms, true);
|
|
||||||
SetTempVarValues(params);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Action::COPY_IMAGE: {
|
|
||||||
ClipboardImageQueueParams params{"", "", _url};
|
|
||||||
obs_queue_task(OBS_TASK_UI, copyImageFromUrl, ¶ms, true);
|
|
||||||
SetTempVarValues(params);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroActionClipboard::SetupTempVars()
|
|
||||||
{
|
|
||||||
MacroAction::SetupTempVars();
|
|
||||||
|
|
||||||
AddTempvar(
|
|
||||||
"mimeType.primary",
|
|
||||||
obs_module_text(
|
|
||||||
"AdvSceneSwitcher.tempVar.clipboard.mimeType.primary"),
|
|
||||||
obs_module_text(
|
|
||||||
"AdvSceneSwitcher.tempVar.clipboard.mimeType.primary.description"));
|
|
||||||
AddTempvar(
|
|
||||||
"mimeType.all",
|
|
||||||
obs_module_text(
|
|
||||||
"AdvSceneSwitcher.tempVar.clipboard.mimeType.all"),
|
|
||||||
obs_module_text(
|
|
||||||
"AdvSceneSwitcher.tempVar.clipboard.mimeType.all.description"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroActionClipboard::SetTempVarValues(const ClipboardQueueParams ¶ms)
|
|
||||||
{
|
|
||||||
SetTempVarValue("mimeType.primary", params.mimeTypePrimary);
|
|
||||||
SetTempVarValue("mimeType.all", params.mimeTypeAll);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MacroActionClipboard::Save(obs_data_t *obj) const
|
|
||||||
{
|
|
||||||
MacroAction::Save(obj);
|
|
||||||
obs_data_set_int(obj, "action", static_cast<int>(_action));
|
|
||||||
_text.Save(obj, "text");
|
|
||||||
_url.Save(obj, "url");
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MacroActionClipboard::Load(obs_data_t *obj)
|
|
||||||
{
|
|
||||||
MacroAction::Load(obj);
|
|
||||||
_action = static_cast<Action>(obs_data_get_int(obj, "action"));
|
|
||||||
_text.Load(obj, "text");
|
|
||||||
_url.Load(obj, "url");
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void populateActionSelection(QComboBox *list)
|
|
||||||
{
|
|
||||||
for (const auto &[action, name] : actionTypes) {
|
|
||||||
list->addItem(obs_module_text(name.c_str()),
|
|
||||||
static_cast<int>(action));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MacroActionClipboardEdit::MacroActionClipboardEdit(
|
|
||||||
QWidget *parent, std::shared_ptr<MacroActionClipboard> entryData)
|
|
||||||
: QWidget(parent),
|
|
||||||
_actions(new FilterComboBox(this)),
|
|
||||||
_text(new VariableLineEdit(this)),
|
|
||||||
_url(new VariableLineEdit(this))
|
|
||||||
{
|
|
||||||
populateActionSelection(_actions);
|
|
||||||
_url->setToolTip(obs_module_text(
|
|
||||||
"AdvSceneSwitcher.action.clipboard.copy.image.url.tooltip"));
|
|
||||||
|
|
||||||
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
|
|
||||||
SLOT(ActionChanged(int)));
|
|
||||||
QWidget::connect(_text, SIGNAL(editingFinished()), this,
|
|
||||||
SLOT(TextChanged()));
|
|
||||||
QWidget::connect(_url, SIGNAL(editingFinished()), this,
|
|
||||||
SLOT(UrlChanged()));
|
|
||||||
|
|
||||||
auto mainLayout = new QHBoxLayout();
|
|
||||||
mainLayout->addWidget(_actions);
|
|
||||||
mainLayout->addWidget(_text);
|
|
||||||
mainLayout->addWidget(_url);
|
|
||||||
setLayout(mainLayout);
|
|
||||||
|
|
||||||
_entryData = entryData;
|
|
||||||
UpdateEntryData();
|
|
||||||
_loading = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroActionClipboardEdit::ActionChanged(int index)
|
|
||||||
{
|
|
||||||
if (_loading || !_entryData) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto lock = LockContext();
|
|
||||||
_entryData->_action = static_cast<MacroActionClipboard::Action>(
|
|
||||||
_actions->itemData(index).toInt());
|
|
||||||
|
|
||||||
SetWidgetVisibility();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroActionClipboardEdit::TextChanged()
|
|
||||||
{
|
|
||||||
if (_loading || !_entryData) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto lock = LockContext();
|
|
||||||
_entryData->_text = _text->text().toStdString();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroActionClipboardEdit::UrlChanged()
|
|
||||||
{
|
|
||||||
if (_loading || !_entryData) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto lock = LockContext();
|
|
||||||
_entryData->_url = _url->text().toStdString();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroActionClipboardEdit::SetWidgetVisibility()
|
|
||||||
{
|
|
||||||
_text->setVisible(_entryData->_action ==
|
|
||||||
MacroActionClipboard::Action::COPY_TEXT);
|
|
||||||
_url->setVisible(_entryData->_action ==
|
|
||||||
MacroActionClipboard::Action::COPY_IMAGE);
|
|
||||||
|
|
||||||
adjustSize();
|
|
||||||
updateGeometry();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroActionClipboardEdit::UpdateEntryData()
|
|
||||||
{
|
|
||||||
if (!_entryData) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_actions->setCurrentIndex(
|
|
||||||
_actions->findData(static_cast<int>(_entryData->_action)));
|
|
||||||
_text->setText(_entryData->_text);
|
|
||||||
_url->setText(_entryData->_url);
|
|
||||||
|
|
||||||
SetWidgetVisibility();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace advss
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "macro-action-edit.hpp"
|
|
||||||
#include "filter-combo-box.hpp"
|
|
||||||
|
|
||||||
#include <variable-line-edit.hpp>
|
|
||||||
|
|
||||||
namespace advss {
|
|
||||||
|
|
||||||
struct ClipboardQueueParams {
|
|
||||||
std::string mimeTypePrimary;
|
|
||||||
std::string mimeTypeAll;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ClipboardTextQueueParams : ClipboardQueueParams {
|
|
||||||
StringVariable text;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ClipboardImageQueueParams : ClipboardQueueParams {
|
|
||||||
StringVariable url;
|
|
||||||
};
|
|
||||||
|
|
||||||
class MacroActionClipboard : public MacroAction {
|
|
||||||
public:
|
|
||||||
MacroActionClipboard(Macro *m) : MacroAction(m) {}
|
|
||||||
static std::shared_ptr<MacroAction> Create(Macro *m)
|
|
||||||
{
|
|
||||||
return std::make_shared<MacroActionClipboard>(m);
|
|
||||||
}
|
|
||||||
std::string GetId() const { return id; };
|
|
||||||
|
|
||||||
bool PerformAction();
|
|
||||||
bool Save(obs_data_t *obj) const;
|
|
||||||
bool Load(obs_data_t *obj);
|
|
||||||
|
|
||||||
enum class Action {
|
|
||||||
COPY_TEXT,
|
|
||||||
COPY_IMAGE,
|
|
||||||
};
|
|
||||||
|
|
||||||
Action _action = Action::COPY_TEXT;
|
|
||||||
|
|
||||||
StringVariable _text = obs_module_text(
|
|
||||||
"AdvSceneSwitcher.action.clipboard.copy.text.text.placeholder");
|
|
||||||
StringVariable _url = obs_module_text(
|
|
||||||
"AdvSceneSwitcher.action.clipboard.copy.image.url.placeholder");
|
|
||||||
|
|
||||||
private:
|
|
||||||
void SetupTempVars();
|
|
||||||
void SetTempVarValues(const ClipboardQueueParams ¶ms);
|
|
||||||
|
|
||||||
static bool _registered;
|
|
||||||
static const std::string id;
|
|
||||||
};
|
|
||||||
|
|
||||||
class MacroActionClipboardEdit : public QWidget {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
MacroActionClipboardEdit(
|
|
||||||
QWidget *parent,
|
|
||||||
std::shared_ptr<MacroActionClipboard> entryData = nullptr);
|
|
||||||
static QWidget *Create(QWidget *parent,
|
|
||||||
std::shared_ptr<MacroAction> action)
|
|
||||||
{
|
|
||||||
return new MacroActionClipboardEdit(
|
|
||||||
parent, std::dynamic_pointer_cast<MacroActionClipboard>(
|
|
||||||
action));
|
|
||||||
}
|
|
||||||
void UpdateEntryData();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
std::shared_ptr<MacroActionClipboard> _entryData;
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void ActionChanged(int index);
|
|
||||||
void TextChanged();
|
|
||||||
void UrlChanged();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void SetWidgetVisibility();
|
|
||||||
|
|
||||||
bool _loading = true;
|
|
||||||
|
|
||||||
FilterComboBox *_actions;
|
|
||||||
VariableLineEdit *_text;
|
|
||||||
VariableLineEdit *_url;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace advss
|
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
#include "macro-action-edit.hpp"
|
|
||||||
#include "macro-helpers.hpp"
|
|
||||||
#include "macro.hpp"
|
|
||||||
#include "macro-properties.hpp"
|
|
||||||
#include "advanced-scene-switcher.hpp"
|
#include "advanced-scene-switcher.hpp"
|
||||||
|
#include "switcher-data.hpp"
|
||||||
|
#include "macro-action-edit.hpp"
|
||||||
#include "macro-action-scene-switch.hpp"
|
#include "macro-action-scene-switch.hpp"
|
||||||
#include "section.hpp"
|
#include "section.hpp"
|
||||||
#include "switch-button.hpp"
|
#include "switch-button.hpp"
|
||||||
@@ -12,9 +10,61 @@
|
|||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
|
std::map<std::string, MacroActionInfo> &MacroActionFactory::GetMap()
|
||||||
|
{
|
||||||
|
static std::map<std::string, MacroActionInfo> _methods;
|
||||||
|
return _methods;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroActionFactory::Register(const std::string &id, MacroActionInfo info)
|
||||||
|
{
|
||||||
|
if (auto it = GetMap().find(id); it == GetMap().end()) {
|
||||||
|
GetMap()[id] = info;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<MacroAction> MacroActionFactory::Create(const std::string &id,
|
||||||
|
Macro *m)
|
||||||
|
{
|
||||||
|
if (auto it = GetMap().find(id); it != GetMap().end())
|
||||||
|
return it->second._createFunc(m);
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget *MacroActionFactory::CreateWidget(const std::string &id,
|
||||||
|
QWidget *parent,
|
||||||
|
std::shared_ptr<MacroAction> action)
|
||||||
|
{
|
||||||
|
if (auto it = GetMap().find(id); it != GetMap().end())
|
||||||
|
return it->second._createWidgetFunc(parent, action);
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string MacroActionFactory::GetActionName(const std::string &id)
|
||||||
|
{
|
||||||
|
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
||||||
|
return it->second._name;
|
||||||
|
}
|
||||||
|
return "unknown action";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string MacroActionFactory::GetIdByName(const QString &name)
|
||||||
|
{
|
||||||
|
for (auto it : GetMap()) {
|
||||||
|
if (name == obs_module_text(it.second._name.c_str())) {
|
||||||
|
return it.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
static inline void populateActionSelection(QComboBox *list)
|
static inline void populateActionSelection(QComboBox *list)
|
||||||
{
|
{
|
||||||
for (const auto &[_, action] : MacroActionFactory::GetActionTypes()) {
|
for (auto &[_, action] : MacroActionFactory::GetActionTypes()) {
|
||||||
QString entry(obs_module_text(action._name.c_str()));
|
QString entry(obs_module_text(action._name.c_str()));
|
||||||
if (list->findText(entry) == -1) {
|
if (list->findText(entry) == -1) {
|
||||||
list->addItem(entry);
|
list->addItem(entry);
|
||||||
@@ -30,8 +80,7 @@ static inline void populateActionSelection(QComboBox *list)
|
|||||||
MacroActionEdit::MacroActionEdit(QWidget *parent,
|
MacroActionEdit::MacroActionEdit(QWidget *parent,
|
||||||
std::shared_ptr<MacroAction> *entryData,
|
std::shared_ptr<MacroAction> *entryData,
|
||||||
const std::string &id)
|
const std::string &id)
|
||||||
: MacroSegmentEdit(GetGlobalMacroProperties()._highlightActions,
|
: MacroSegmentEdit(switcher->macroProperties._highlightActions, parent),
|
||||||
parent),
|
|
||||||
_actionSelection(new FilterComboBox()),
|
_actionSelection(new FilterComboBox()),
|
||||||
_enable(new SwitchButton()),
|
_enable(new SwitchButton()),
|
||||||
_entryData(entryData)
|
_entryData(entryData)
|
||||||
@@ -85,7 +134,7 @@ void MacroActionEdit::ActionSelectionChanged(const QString &text)
|
|||||||
auto idx = _entryData->get()->GetIndex();
|
auto idx = _entryData->get()->GetIndex();
|
||||||
auto macro = _entryData->get()->GetMacro();
|
auto macro = _entryData->get()->GetMacro();
|
||||||
{
|
{
|
||||||
auto lock = LockContext();
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
_entryData->reset();
|
_entryData->reset();
|
||||||
*_entryData = MacroActionFactory::Create(id, macro);
|
*_entryData = MacroActionFactory::Create(id, macro);
|
||||||
(*_entryData)->SetIndex(idx);
|
(*_entryData)->SetIndex(idx);
|
||||||
@@ -136,7 +185,7 @@ void MacroActionEdit::ActionEnableChanged(bool value)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lock = LockContext();
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
(*_entryData)->SetEnabled(value);
|
(*_entryData)->SetEnabled(value);
|
||||||
SetDisableEffect(!value);
|
SetDisableEffect(!value);
|
||||||
}
|
}
|
||||||
@@ -180,7 +229,7 @@ void AdvSceneSwitcher::AddMacroAction(int idx)
|
|||||||
id = temp.GetId();
|
id = temp.GetId();
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto lock = LockContext();
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
macro->Actions().emplace(
|
macro->Actions().emplace(
|
||||||
macro->Actions().begin() + idx,
|
macro->Actions().begin() + idx,
|
||||||
MacroActionFactory::Create(id, macro.get()));
|
MacroActionFactory::Create(id, macro.get()));
|
||||||
@@ -231,11 +280,11 @@ void AdvSceneSwitcher::RemoveMacroAction(int idx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto lock = LockContext();
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
ui->actionsList->Remove(idx);
|
ui->actionsList->Remove(idx);
|
||||||
macro->Actions().erase(macro->Actions().begin() + idx);
|
macro->Actions().erase(macro->Actions().begin() + idx);
|
||||||
SetMacroAbortWait(true);
|
switcher->abortMacroWait = true;
|
||||||
GetMacroWaitCV().notify_all();
|
switcher->macroWaitCv.notify_all();
|
||||||
macro->UpdateActionIndices();
|
macro->UpdateActionIndices();
|
||||||
SetActionData(*macro);
|
SetActionData(*macro);
|
||||||
}
|
}
|
||||||
@@ -376,7 +425,7 @@ void AdvSceneSwitcher::SwapActions(Macro *m, int pos1, int pos2)
|
|||||||
std::swap(pos1, pos2);
|
std::swap(pos1, pos2);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lock = LockContext();
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
iter_swap(m->Actions().begin() + pos1, m->Actions().begin() + pos2);
|
iter_swap(m->Actions().begin() + pos1, m->Actions().begin() + pos2);
|
||||||
m->UpdateActionIndices();
|
m->UpdateActionIndices();
|
||||||
auto widget1 = static_cast<MacroActionEdit *>(
|
auto widget1 = static_cast<MacroActionEdit *>(
|
||||||
@@ -436,7 +485,7 @@ void AdvSceneSwitcher::MacroElseActionReorder(int to, int from)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto lock = LockContext();
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
auto action = macro->ElseActions().at(from);
|
auto action = macro->ElseActions().at(from);
|
||||||
macro->ElseActions().erase(macro->ElseActions().begin() + from);
|
macro->ElseActions().erase(macro->ElseActions().begin() + from);
|
||||||
macro->ElseActions().insert(macro->ElseActions().begin() + to,
|
macro->ElseActions().insert(macro->ElseActions().begin() + to,
|
||||||
@@ -469,7 +518,7 @@ void AdvSceneSwitcher::AddMacroElseAction(int idx)
|
|||||||
id = temp.GetId();
|
id = temp.GetId();
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto lock = LockContext();
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
macro->ElseActions().emplace(
|
macro->ElseActions().emplace(
|
||||||
macro->ElseActions().begin() + idx,
|
macro->ElseActions().begin() + idx,
|
||||||
MacroActionFactory::Create(id, macro.get()));
|
MacroActionFactory::Create(id, macro.get()));
|
||||||
@@ -501,11 +550,11 @@ void AdvSceneSwitcher::RemoveMacroElseAction(int idx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto lock = LockContext();
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
ui->elseActionsList->Remove(idx);
|
ui->elseActionsList->Remove(idx);
|
||||||
macro->ElseActions().erase(macro->ElseActions().begin() + idx);
|
macro->ElseActions().erase(macro->ElseActions().begin() + idx);
|
||||||
SetMacroAbortWait(true);
|
switcher->abortMacroWait = true;
|
||||||
GetMacroWaitCV().notify_all();
|
switcher->macroWaitCv.notify_all();
|
||||||
macro->UpdateElseActionIndices();
|
macro->UpdateElseActionIndices();
|
||||||
SetActionData(*macro);
|
SetActionData(*macro);
|
||||||
}
|
}
|
||||||
@@ -523,7 +572,7 @@ void AdvSceneSwitcher::SwapElseActions(Macro *m, int pos1, int pos2)
|
|||||||
std::swap(pos1, pos2);
|
std::swap(pos1, pos2);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lock = LockContext();
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
iter_swap(m->ElseActions().begin() + pos1,
|
iter_swap(m->ElseActions().begin() + pos1,
|
||||||
m->ElseActions().begin() + pos2);
|
m->ElseActions().begin() + pos2);
|
||||||
m->UpdateElseActionIndices();
|
m->UpdateElseActionIndices();
|
||||||
@@ -586,7 +635,7 @@ void AdvSceneSwitcher::MacroActionReorder(int to, int from)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto lock = LockContext();
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
auto action = macro->Actions().at(from);
|
auto action = macro->Actions().at(from);
|
||||||
macro->Actions().erase(macro->Actions().begin() + from);
|
macro->Actions().erase(macro->Actions().begin() + from);
|
||||||
macro->Actions().insert(macro->Actions().begin() + to, action);
|
macro->Actions().insert(macro->Actions().begin() + to, action);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "macro-action.hpp"
|
#include "macro-action.hpp"
|
||||||
#include "macro-action-factory.hpp"
|
|
||||||
#include "filter-combo-box.hpp"
|
#include "filter-combo-box.hpp"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -9,6 +8,32 @@ namespace advss {
|
|||||||
|
|
||||||
class SwitchButton;
|
class SwitchButton;
|
||||||
|
|
||||||
|
struct MacroActionInfo {
|
||||||
|
using TCreateMethod = std::shared_ptr<MacroAction> (*)(Macro *m);
|
||||||
|
using TCreateWidgetMethod = QWidget *(*)(QWidget *parent,
|
||||||
|
std::shared_ptr<MacroAction>);
|
||||||
|
TCreateMethod _createFunc = nullptr;
|
||||||
|
TCreateWidgetMethod _createWidgetFunc = nullptr;
|
||||||
|
std::string _name;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MacroActionFactory {
|
||||||
|
public:
|
||||||
|
MacroActionFactory() = delete;
|
||||||
|
|
||||||
|
static bool Register(const std::string &id, MacroActionInfo);
|
||||||
|
static std::shared_ptr<MacroAction> Create(const std::string &id,
|
||||||
|
Macro *m);
|
||||||
|
static QWidget *CreateWidget(const std::string &id, QWidget *parent,
|
||||||
|
std::shared_ptr<MacroAction> action);
|
||||||
|
static auto GetActionTypes() { return GetMap(); }
|
||||||
|
static std::string GetActionName(const std::string &id);
|
||||||
|
static std::string GetIdByName(const QString &name);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static std::map<std::string, MacroActionInfo> &GetMap();
|
||||||
|
};
|
||||||
|
|
||||||
class MacroActionEdit : public MacroSegmentEdit {
|
class MacroActionEdit : public MacroSegmentEdit {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
|||||||
@@ -1,57 +0,0 @@
|
|||||||
#include "macro-action-factory.hpp"
|
|
||||||
|
|
||||||
namespace advss {
|
|
||||||
|
|
||||||
std::map<std::string, MacroActionInfo> &MacroActionFactory::GetMap()
|
|
||||||
{
|
|
||||||
static std::map<std::string, MacroActionInfo> _methods;
|
|
||||||
return _methods;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MacroActionFactory::Register(const std::string &id, MacroActionInfo info)
|
|
||||||
{
|
|
||||||
if (auto it = GetMap().find(id); it == GetMap().end()) {
|
|
||||||
GetMap()[id] = info;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<MacroAction> MacroActionFactory::Create(const std::string &id,
|
|
||||||
Macro *m)
|
|
||||||
{
|
|
||||||
if (auto it = GetMap().find(id); it != GetMap().end())
|
|
||||||
return it->second._create(m);
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
QWidget *MacroActionFactory::CreateWidget(const std::string &id,
|
|
||||||
QWidget *parent,
|
|
||||||
std::shared_ptr<MacroAction> action)
|
|
||||||
{
|
|
||||||
if (auto it = GetMap().find(id); it != GetMap().end())
|
|
||||||
return it->second._createWidget(parent, action);
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string MacroActionFactory::GetActionName(const std::string &id)
|
|
||||||
{
|
|
||||||
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
|
||||||
return it->second._name;
|
|
||||||
}
|
|
||||||
return "unknown action";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string MacroActionFactory::GetIdByName(const QString &name)
|
|
||||||
{
|
|
||||||
for (auto it : GetMap()) {
|
|
||||||
if (name == obs_module_text(it.second._name.c_str())) {
|
|
||||||
return it.first;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace advss
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "macro-action.hpp"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace advss {
|
|
||||||
|
|
||||||
struct MacroActionInfo {
|
|
||||||
using CreateAction = std::shared_ptr<MacroAction> (*)(Macro *m);
|
|
||||||
using CreateActionWidget = QWidget *(*)(QWidget *parent,
|
|
||||||
std::shared_ptr<MacroAction>);
|
|
||||||
CreateAction _create = nullptr;
|
|
||||||
CreateActionWidget _createWidget = nullptr;
|
|
||||||
std::string _name;
|
|
||||||
};
|
|
||||||
|
|
||||||
class MacroActionFactory {
|
|
||||||
public:
|
|
||||||
MacroActionFactory() = delete;
|
|
||||||
|
|
||||||
static bool Register(const std::string &id, MacroActionInfo);
|
|
||||||
static std::shared_ptr<MacroAction> Create(const std::string &id,
|
|
||||||
Macro *m);
|
|
||||||
static QWidget *CreateWidget(const std::string &id, QWidget *parent,
|
|
||||||
std::shared_ptr<MacroAction> action);
|
|
||||||
static auto GetActionTypes() { return GetMap(); }
|
|
||||||
static std::string GetActionName(const std::string &id);
|
|
||||||
static std::string GetIdByName(const QString &name);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static std::map<std::string, MacroActionInfo> &GetMap();
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace advss
|
|
||||||
@@ -424,16 +424,11 @@ void MacroActionFilterEdit::SetWidgetVisibility()
|
|||||||
_entryData->_settingsInputMethod ==
|
_entryData->_settingsInputMethod ==
|
||||||
MacroActionFilter::SettingsInputMethod::
|
MacroActionFilter::SettingsInputMethod::
|
||||||
INDIVIDUAL_TEMPVAR);
|
INDIVIDUAL_TEMPVAR);
|
||||||
|
_manualSettingValue->setVisible(
|
||||||
if (_entryData->_action == MacroActionFilter::Action::SETTINGS &&
|
_entryData->_action == MacroActionFilter::Action::SETTINGS &&
|
||||||
_entryData->_settingsInputMethod ==
|
_entryData->_settingsInputMethod ==
|
||||||
MacroActionFilter::SettingsInputMethod::INDIVIDUAL_MANUAL) {
|
MacroActionFilter::SettingsInputMethod::
|
||||||
RemoveStretchIfPresent(_settingsLayout);
|
INDIVIDUAL_MANUAL);
|
||||||
_manualSettingValue->show();
|
|
||||||
} else {
|
|
||||||
AddStretchIfNecessary(_settingsLayout);
|
|
||||||
_manualSettingValue->hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
adjustSize();
|
adjustSize();
|
||||||
updateGeometry();
|
updateGeometry();
|
||||||
|
|||||||
@@ -14,14 +14,14 @@ bool MacroActionHotkey::_registered = MacroActionFactory::Register(
|
|||||||
{MacroActionHotkey::Create, MacroActionHotkeyEdit::Create,
|
{MacroActionHotkey::Create, MacroActionHotkeyEdit::Create,
|
||||||
"AdvSceneSwitcher.action.hotkey"});
|
"AdvSceneSwitcher.action.hotkey"});
|
||||||
|
|
||||||
static const std::map<MacroActionHotkey::Action, std::string> actionTypes = {
|
const static std::map<MacroActionHotkey::Action, std::string> actionTypes = {
|
||||||
{MacroActionHotkey::Action::OBS_HOTKEY,
|
{MacroActionHotkey::Action::OBS_HOTKEY,
|
||||||
"AdvSceneSwitcher.action.hotkey.type.obs"},
|
"AdvSceneSwitcher.action.hotkey.type.obs"},
|
||||||
{MacroActionHotkey::Action::CUSTOM,
|
{MacroActionHotkey::Action::CUSTOM,
|
||||||
"AdvSceneSwitcher.action.hotkey.type.custom"},
|
"AdvSceneSwitcher.action.hotkey.type.custom"},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const std::map<obs_hotkey_registerer_type, std::string> hotkeyTypes = {
|
const static std::map<obs_hotkey_registerer_type, std::string> hotkeyTypes = {
|
||||||
{OBS_HOTKEY_REGISTERER_FRONTEND,
|
{OBS_HOTKEY_REGISTERER_FRONTEND,
|
||||||
"AdvSceneSwitcher.action.hotkey.type.obs.type.frontend"},
|
"AdvSceneSwitcher.action.hotkey.type.obs.type.frontend"},
|
||||||
{OBS_HOTKEY_REGISTERER_SOURCE,
|
{OBS_HOTKEY_REGISTERER_SOURCE,
|
||||||
@@ -34,7 +34,7 @@ static const std::map<obs_hotkey_registerer_type, std::string> hotkeyTypes = {
|
|||||||
"AdvSceneSwitcher.action.hotkey.type.obs.type.service"},
|
"AdvSceneSwitcher.action.hotkey.type.obs.type.service"},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const std::unordered_map<HotkeyType, long> keyTable = {
|
static std::unordered_map<HotkeyType, long> keyTable = {
|
||||||
// Chars
|
// Chars
|
||||||
{HotkeyType::Key_A, OBS_KEY_A},
|
{HotkeyType::Key_A, OBS_KEY_A},
|
||||||
{HotkeyType::Key_B, OBS_KEY_B},
|
{HotkeyType::Key_B, OBS_KEY_B},
|
||||||
@@ -75,9 +75,6 @@ static const std::unordered_map<HotkeyType, long> keyTable = {
|
|||||||
{HotkeyType::Key_8, OBS_KEY_8},
|
{HotkeyType::Key_8, OBS_KEY_8},
|
||||||
{HotkeyType::Key_9, OBS_KEY_9},
|
{HotkeyType::Key_9, OBS_KEY_9},
|
||||||
|
|
||||||
// Other
|
|
||||||
{HotkeyType::Key_Tilde, OBS_KEY_ASCIITILDE},
|
|
||||||
|
|
||||||
{HotkeyType::Key_F1, OBS_KEY_F1},
|
{HotkeyType::Key_F1, OBS_KEY_F1},
|
||||||
{HotkeyType::Key_F2, OBS_KEY_F2},
|
{HotkeyType::Key_F2, OBS_KEY_F2},
|
||||||
{HotkeyType::Key_F3, OBS_KEY_F3},
|
{HotkeyType::Key_F3, OBS_KEY_F3},
|
||||||
@@ -528,7 +525,6 @@ static inline void populateKeySelection(QComboBox *list)
|
|||||||
list->addItem("NumpadDivide");
|
list->addItem("NumpadDivide");
|
||||||
list->addItem("NumpadDecimal");
|
list->addItem("NumpadDecimal");
|
||||||
list->addItem("NumpadEnter");
|
list->addItem("NumpadEnter");
|
||||||
list->addItem("Tilde");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void populateActionSelection(QComboBox *list)
|
static void populateActionSelection(QComboBox *list)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "macro-action-http.hpp"
|
#include "macro-action-http.hpp"
|
||||||
|
#include "switcher-data.hpp"
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
#include "curl-helper.hpp"
|
#include "curl-helper.hpp"
|
||||||
|
|
||||||
@@ -35,44 +36,44 @@ void MacroActionHttp::SetupHeaders()
|
|||||||
}
|
}
|
||||||
struct curl_slist *headers = nullptr;
|
struct curl_slist *headers = nullptr;
|
||||||
for (auto &header : _headers) {
|
for (auto &header : _headers) {
|
||||||
headers = CurlHelper::SlistAppend(headers, header.c_str());
|
headers = switcher->curl.SlistAppend(headers, header.c_str());
|
||||||
}
|
}
|
||||||
if (!_headers.empty()) {
|
if (!_headers.empty()) {
|
||||||
CurlHelper::SetOpt(CURLOPT_HTTPHEADER, headers);
|
switcher->curl.SetOpt(CURLOPT_HTTPHEADER, headers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroActionHttp::Get()
|
void MacroActionHttp::Get()
|
||||||
{
|
{
|
||||||
CurlHelper::SetOpt(CURLOPT_URL, _url.c_str());
|
switcher->curl.SetOpt(CURLOPT_URL, _url.c_str());
|
||||||
CurlHelper::SetOpt(CURLOPT_HTTPGET, 1L);
|
switcher->curl.SetOpt(CURLOPT_HTTPGET, 1L);
|
||||||
CurlHelper::SetOpt(CURLOPT_TIMEOUT_MS, _timeout.Milliseconds());
|
switcher->curl.SetOpt(CURLOPT_TIMEOUT_MS, _timeout.Milliseconds());
|
||||||
SetupHeaders();
|
SetupHeaders();
|
||||||
|
|
||||||
std::string response;
|
std::string response;
|
||||||
if (IsReferencedInVars()) {
|
if (IsReferencedInVars()) {
|
||||||
CurlHelper::SetOpt(CURLOPT_WRITEFUNCTION, WriteCB);
|
switcher->curl.SetOpt(CURLOPT_WRITEFUNCTION, WriteCB);
|
||||||
} else {
|
} else {
|
||||||
CurlHelper::SetOpt(CURLOPT_WRITEFUNCTION, DropCB);
|
switcher->curl.SetOpt(CURLOPT_WRITEFUNCTION, DropCB);
|
||||||
}
|
}
|
||||||
CurlHelper::SetOpt(CURLOPT_WRITEDATA, &response);
|
switcher->curl.SetOpt(CURLOPT_WRITEDATA, &response);
|
||||||
CurlHelper::Perform();
|
switcher->curl.Perform();
|
||||||
|
|
||||||
SetVariableValue(response);
|
SetVariableValue(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroActionHttp::Post()
|
void MacroActionHttp::Post()
|
||||||
{
|
{
|
||||||
CurlHelper::SetOpt(CURLOPT_URL, _url.c_str());
|
switcher->curl.SetOpt(CURLOPT_URL, _url.c_str());
|
||||||
CurlHelper::SetOpt(CURLOPT_POSTFIELDS, _data.c_str());
|
switcher->curl.SetOpt(CURLOPT_POSTFIELDS, _data.c_str());
|
||||||
CurlHelper::SetOpt(CURLOPT_TIMEOUT_MS, _timeout.Milliseconds());
|
switcher->curl.SetOpt(CURLOPT_TIMEOUT_MS, _timeout.Milliseconds());
|
||||||
SetupHeaders();
|
SetupHeaders();
|
||||||
CurlHelper::Perform();
|
switcher->curl.Perform();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroActionHttp::PerformAction()
|
bool MacroActionHttp::PerformAction()
|
||||||
{
|
{
|
||||||
if (!CurlHelper::Initialized()) {
|
if (!switcher->curl.Initialized()) {
|
||||||
blog(LOG_WARNING,
|
blog(LOG_WARNING,
|
||||||
"cannot perform http action (curl not found)");
|
"cannot perform http action (curl not found)");
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
#include "macro-action-plugin-state.hpp"
|
#include "macro-action-plugin-state.hpp"
|
||||||
#include "plugin-state-helpers.hpp"
|
#include "switcher-data.hpp"
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <condition_variable>
|
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
|
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
@@ -28,38 +27,40 @@ const static std::map<PluginStateAction, std::string> actionTypes = {
|
|||||||
"AdvSceneSwitcher.action.pluginState.type.terminate"},
|
"AdvSceneSwitcher.action.pluginState.type.terminate"},
|
||||||
};
|
};
|
||||||
|
|
||||||
const static std::map<NoMatchBehavior, std::string> noMatchValues = {
|
const static std::map<SwitcherData::NoMatch, std::string> noMatchValues = {
|
||||||
{NoMatchBehavior::NO_SWITCH,
|
{SwitcherData::NoMatch::NO_SWITCH,
|
||||||
"AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.dontSwitch"},
|
"AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.dontSwitch"},
|
||||||
{NoMatchBehavior::SWITCH,
|
{SwitcherData::NoMatch::SWITCH,
|
||||||
"AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchTo"},
|
"AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchTo"},
|
||||||
{NoMatchBehavior::RANDOM_SWITCH,
|
{SwitcherData::NoMatch::RANDOM_SWITCH,
|
||||||
"AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchToRandom"},
|
"AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchToRandom"},
|
||||||
};
|
};
|
||||||
|
|
||||||
static void stopPlugin()
|
static void stopPlugin()
|
||||||
{
|
{
|
||||||
std::thread t([]() { StopPlugin(); });
|
std::thread t([]() { switcher->Stop(); });
|
||||||
t.detach();
|
t.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void importSettings(const std::string &path)
|
static void importSettings(const std::string &path)
|
||||||
{
|
{
|
||||||
if (SettingsWindowIsOpened()) {
|
if (switcher->settingsWindowOpened) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
OBSDataAutoRelease obj = obs_data_create_from_json_file(path.c_str());
|
obs_data_t *obj = obs_data_create_from_json_file(path.c_str());
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LoadPluginSettings(obj);
|
switcher->LoadSettings(obj);
|
||||||
|
obs_data_release(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setNoMatchBehaviour(int value, OBSWeakSource &scene)
|
static void setNoMatchBehaviour(int value, OBSWeakSource &scene)
|
||||||
{
|
{
|
||||||
SetPluginNoMatchBehavior(static_cast<NoMatchBehavior>(value));
|
switcher->switchIfNotMatching =
|
||||||
if (GetPluginNoMatchBehavior() == NoMatchBehavior::SWITCH) {
|
static_cast<SwitcherData::NoMatch>(value);
|
||||||
SetNoMatchScene(scene);
|
if (switcher->switchIfNotMatching == SwitcherData::NoMatch::SWITCH) {
|
||||||
|
switcher->nonMatchingScene = scene;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,8 +342,8 @@ void MacroActionPluginStateEdit::SetWidgetVisibility()
|
|||||||
break;
|
break;
|
||||||
case PluginStateAction::NO_MATCH_BEHAVIOUR:
|
case PluginStateAction::NO_MATCH_BEHAVIOUR:
|
||||||
_values->show();
|
_values->show();
|
||||||
if (static_cast<NoMatchBehavior>(_entryData->_value) ==
|
if (static_cast<SwitcherData::NoMatch>(_entryData->_value) ==
|
||||||
NoMatchBehavior::SWITCH) {
|
SwitcherData::NoMatch::SWITCH) {
|
||||||
_scenes->show();
|
_scenes->show();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -14,14 +14,9 @@ bool MacroActionRun::_registered = MacroActionFactory::Register(
|
|||||||
|
|
||||||
bool MacroActionRun::PerformAction()
|
bool MacroActionRun::PerformAction()
|
||||||
{
|
{
|
||||||
if (_wait) {
|
bool procStarted = QProcess::startDetached(
|
||||||
_procConfig.StartProcessAndWait(_timeout.Milliseconds());
|
QString::fromStdString(_procConfig.Path()), _procConfig.Args(),
|
||||||
return true;
|
QString::fromStdString(_procConfig.WorkingDir()));
|
||||||
}
|
|
||||||
|
|
||||||
bool procStarted = _procConfig.StartProcessDetached();
|
|
||||||
|
|
||||||
// Fall back to using default application to open given file
|
|
||||||
if (!procStarted && _procConfig.Args().empty()) {
|
if (!procStarted && _procConfig.Args().empty()) {
|
||||||
vblog(LOG_INFO, "run \"%s\" using QDesktopServices",
|
vblog(LOG_INFO, "run \"%s\" using QDesktopServices",
|
||||||
_procConfig.Path().c_str());
|
_procConfig.Path().c_str());
|
||||||
@@ -40,9 +35,6 @@ bool MacroActionRun::Save(obs_data_t *obj) const
|
|||||||
{
|
{
|
||||||
MacroAction::Save(obj);
|
MacroAction::Save(obj);
|
||||||
_procConfig.Save(obj);
|
_procConfig.Save(obj);
|
||||||
_timeout.Save(obj);
|
|
||||||
obs_data_set_bool(obj, "wait", _wait);
|
|
||||||
obs_data_set_int(obj, "version", 1);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,12 +42,6 @@ bool MacroActionRun::Load(obs_data_t *obj)
|
|||||||
{
|
{
|
||||||
MacroAction::Load(obj);
|
MacroAction::Load(obj);
|
||||||
_procConfig.Load(obj);
|
_procConfig.Load(obj);
|
||||||
// TODO: Remove this fallback in a future version
|
|
||||||
if (!obs_data_has_user_value(obj, "version")) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
_timeout.Load(obj);
|
|
||||||
_wait = obs_data_get_bool(obj, "wait");
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,30 +52,14 @@ std::string MacroActionRun::GetShortDesc() const
|
|||||||
|
|
||||||
MacroActionRunEdit::MacroActionRunEdit(
|
MacroActionRunEdit::MacroActionRunEdit(
|
||||||
QWidget *parent, std::shared_ptr<MacroActionRun> entryData)
|
QWidget *parent, std::shared_ptr<MacroActionRun> entryData)
|
||||||
: QWidget(parent),
|
: QWidget(parent), _procConfig(new ProcessConfigEdit(this))
|
||||||
_procConfig(new ProcessConfigEdit(this)),
|
|
||||||
_waitLayout(new QHBoxLayout()),
|
|
||||||
_wait(new QCheckBox()),
|
|
||||||
_timeout(new DurationSelection(this, true, 0.1))
|
|
||||||
{
|
{
|
||||||
QWidget::connect(_procConfig,
|
QWidget::connect(_procConfig,
|
||||||
SIGNAL(ConfigChanged(const ProcessConfig &)), this,
|
SIGNAL(ConfigChanged(const ProcessConfig &)), this,
|
||||||
SLOT(ProcessConfigChanged(const ProcessConfig &)));
|
SLOT(ProcessConfigChanged(const ProcessConfig &)));
|
||||||
QWidget::connect(_procConfig, SIGNAL(AdvancedSettingsEnabled()), this,
|
|
||||||
SLOT(ProcessConfigAdvancedSettingsShown()));
|
|
||||||
QWidget::connect(_wait, SIGNAL(stateChanged(int)), this,
|
|
||||||
SLOT(WaitChanged(int)));
|
|
||||||
QWidget::connect(_timeout, SIGNAL(DurationChanged(const Duration &)),
|
|
||||||
this, SLOT(TimeoutChanged(const Duration &)));
|
|
||||||
|
|
||||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.run.entry.wait"),
|
auto *layout = new QVBoxLayout;
|
||||||
_waitLayout,
|
|
||||||
{{"{{wait}}", _wait}, {"{{timeout}}", _timeout}});
|
|
||||||
SetLayoutVisible(_waitLayout, false);
|
|
||||||
|
|
||||||
auto layout = new QVBoxLayout;
|
|
||||||
layout->addWidget(_procConfig);
|
layout->addWidget(_procConfig);
|
||||||
layout->addLayout(_waitLayout);
|
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
|
|
||||||
_entryData = entryData;
|
_entryData = entryData;
|
||||||
@@ -103,31 +73,6 @@ void MacroActionRunEdit::UpdateEntryData()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_procConfig->SetProcessConfig(_entryData->_procConfig);
|
_procConfig->SetProcessConfig(_entryData->_procConfig);
|
||||||
_wait->setChecked(_entryData->_wait);
|
|
||||||
_timeout->SetDuration(_entryData->_timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroActionRunEdit::ProcessConfigAdvancedSettingsShown()
|
|
||||||
{
|
|
||||||
SetLayoutVisible(_waitLayout, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroActionRunEdit::WaitChanged(int value)
|
|
||||||
{
|
|
||||||
if (_loading || !_entryData) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto lock = LockContext();
|
|
||||||
_entryData->_wait = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroActionRunEdit::TimeoutChanged(const Duration &timeout)
|
|
||||||
{
|
|
||||||
if (_loading || !_entryData) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto lock = LockContext();
|
|
||||||
_entryData->_timeout = timeout;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroActionRunEdit::ProcessConfigChanged(const ProcessConfig &conf)
|
void MacroActionRunEdit::ProcessConfigChanged(const ProcessConfig &conf)
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "macro-action-edit.hpp"
|
#include "macro-action-edit.hpp"
|
||||||
#include "process-config.hpp"
|
#include "process-config.hpp"
|
||||||
#include "duration-control.hpp"
|
|
||||||
|
|
||||||
#include <QCheckBox>
|
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
@@ -22,8 +19,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
ProcessConfig _procConfig;
|
ProcessConfig _procConfig;
|
||||||
bool _wait = false;
|
|
||||||
Duration _timeout = 1;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
@@ -47,19 +42,14 @@ public:
|
|||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void ProcessConfigChanged(const ProcessConfig &);
|
void ProcessConfigChanged(const ProcessConfig &);
|
||||||
void ProcessConfigAdvancedSettingsShown();
|
|
||||||
void WaitChanged(int);
|
|
||||||
void TimeoutChanged(const Duration &);
|
|
||||||
signals:
|
signals:
|
||||||
void HeaderInfoChanged(const QString &);
|
void HeaderInfoChanged(const QString &);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::shared_ptr<MacroActionRun> _entryData;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ProcessConfigEdit *_procConfig;
|
ProcessConfigEdit *_procConfig;
|
||||||
QHBoxLayout *_waitLayout;
|
|
||||||
QCheckBox *_wait;
|
|
||||||
DurationSelection *_timeout;
|
|
||||||
|
|
||||||
std::shared_ptr<MacroActionRun> _entryData;
|
|
||||||
bool _loading = true;
|
bool _loading = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "macro-action-scene-collection.hpp"
|
#include "macro-action-scene-collection.hpp"
|
||||||
#include "plugin-state-helpers.hpp"
|
#include "switcher-data.hpp"
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
@@ -17,7 +17,7 @@ bool MacroActionSceneCollection::PerformAction()
|
|||||||
// Changing the scene collection will also reload the settings of the
|
// Changing the scene collection will also reload the settings of the
|
||||||
// scene switcher, so to avoid issues of not being able to change
|
// scene switcher, so to avoid issues of not being able to change
|
||||||
// settings ignore this action if the settings dialog is opened.
|
// settings ignore this action if the settings dialog is opened.
|
||||||
if (SettingsWindowIsOpened()) {
|
if (switcher->settingsWindowOpened) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
obs_frontend_set_current_scene_collection(_sceneCollection.c_str());
|
obs_frontend_set_current_scene_collection(_sceneCollection.c_str());
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
#include "macro-action-scene-switch.hpp"
|
#include "macro-action-scene-switch.hpp"
|
||||||
#include "macro-helpers.hpp"
|
#include "switcher-data.hpp"
|
||||||
#include "plugin-state-helpers.hpp"
|
|
||||||
#include "macro.hpp"
|
|
||||||
#include "scene-switch-helpers.hpp"
|
#include "scene-switch-helpers.hpp"
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
|
|
||||||
@@ -9,7 +7,7 @@ namespace advss {
|
|||||||
|
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
const std::string MacroActionSwitchScene::id = GetSceneSwitchActionId().data();
|
const std::string MacroActionSwitchScene::id = "scene_switch";
|
||||||
|
|
||||||
bool MacroActionSwitchScene::_registered = MacroActionFactory::Register(
|
bool MacroActionSwitchScene::_registered = MacroActionFactory::Register(
|
||||||
MacroActionSwitchScene::id,
|
MacroActionSwitchScene::id,
|
||||||
@@ -35,9 +33,9 @@ static void waitForTransitionChange(OBSWeakSource &transition,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool stillTransitioning = true;
|
bool stillTransitioning = true;
|
||||||
while (stillTransitioning && !MacroWaitShouldAbort() &&
|
while (stillTransitioning && !switcher->abortMacroWait &&
|
||||||
!macro->GetStop()) {
|
!macro->GetStop()) {
|
||||||
GetMacroTransitionCV().wait_for(*lock, time);
|
switcher->macroTransitionCv.wait_for(*lock, time);
|
||||||
float t = obs_transition_get_time(source);
|
float t = obs_transition_get_time(source);
|
||||||
stillTransitioning = t < 1.0f && t > 0.0f;
|
stillTransitioning = t < 1.0f && t > 0.0f;
|
||||||
}
|
}
|
||||||
@@ -51,8 +49,8 @@ static void waitForTransitionChangeFixedDuration(
|
|||||||
auto time = std::chrono::high_resolution_clock::now() +
|
auto time = std::chrono::high_resolution_clock::now() +
|
||||||
std::chrono::milliseconds(duration);
|
std::chrono::milliseconds(duration);
|
||||||
|
|
||||||
while (!MacroWaitShouldAbort() && !macro->GetStop()) {
|
while (!switcher->abortMacroWait && !macro->GetStop()) {
|
||||||
if (GetMacroTransitionCV().wait_until(*lock, time) ==
|
if (switcher->macroTransitionCv.wait_until(*lock, time) ==
|
||||||
std::cv_status::timeout) {
|
std::cv_status::timeout) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -93,16 +91,11 @@ static OBSWeakSource getOverrideTransition(OBSWeakSource &scene)
|
|||||||
return transition;
|
return transition;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getExpectedTransitionDuration(OBSWeakSource &scene,
|
static int getExpectedTransitionDuration(OBSWeakSource &scene, OBSWeakSource &t,
|
||||||
OBSWeakSource &transiton_,
|
|
||||||
double duration)
|
double duration)
|
||||||
{
|
{
|
||||||
OBSWeakSource transition = transiton_;
|
OBSWeakSource transition = t;
|
||||||
|
if (!switcher->transitionOverrideOverride) {
|
||||||
// If we are not modifying the transition override, we will have to
|
|
||||||
// check, if a transition override is set by the user and use its
|
|
||||||
// duration instead
|
|
||||||
if (!ShouldModifyTransitionOverrides()) {
|
|
||||||
auto overrideTransition = getOverrideTransition(scene);
|
auto overrideTransition = getOverrideTransition(scene);
|
||||||
if (overrideTransition) {
|
if (overrideTransition) {
|
||||||
transition = overrideTransition;
|
transition = overrideTransition;
|
||||||
@@ -111,7 +104,6 @@ static int getExpectedTransitionDuration(OBSWeakSource &scene,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isUsingFixedLengthTransition(transition)) {
|
if (isUsingFixedLengthTransition(transition)) {
|
||||||
return -1; // no API is available to access the fixed duration
|
return -1; // no API is available to access the fixed duration
|
||||||
}
|
}
|
||||||
@@ -126,9 +118,9 @@ bool MacroActionSwitchScene::WaitForTransition(OBSWeakSource &scene,
|
|||||||
{
|
{
|
||||||
const int expectedTransitionDuration = getExpectedTransitionDuration(
|
const int expectedTransitionDuration = getExpectedTransitionDuration(
|
||||||
scene, transition, _duration.Seconds());
|
scene, transition, _duration.Seconds());
|
||||||
SetMacroAbortWait(false);
|
switcher->abortMacroWait = false;
|
||||||
|
|
||||||
std::unique_lock<std::mutex> lock(*GetMutex());
|
std::unique_lock<std::mutex> lock(switcher->m);
|
||||||
if (expectedTransitionDuration < 0) {
|
if (expectedTransitionDuration < 0) {
|
||||||
waitForTransitionChange(transition, &lock, GetMacro());
|
waitForTransitionChange(transition, &lock, GetMacro());
|
||||||
} else {
|
} else {
|
||||||
@@ -136,7 +128,7 @@ bool MacroActionSwitchScene::WaitForTransition(OBSWeakSource &scene,
|
|||||||
&lock, GetMacro());
|
&lock, GetMacro());
|
||||||
}
|
}
|
||||||
|
|
||||||
return !MacroWaitShouldAbort();
|
return !switcher->abortMacroWait;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroActionSwitchScene::PerformAction()
|
bool MacroActionSwitchScene::PerformAction()
|
||||||
@@ -153,7 +145,7 @@ bool MacroActionSwitchScene::PerformAction()
|
|||||||
auto transition = _transition.GetTransition();
|
auto transition = _transition.GetTransition();
|
||||||
SwitchScene({scene, transition, (int)(_duration.Milliseconds())},
|
SwitchScene({scene, transition, (int)(_duration.Milliseconds())},
|
||||||
obs_frontend_preview_program_mode_active());
|
obs_frontend_preview_program_mode_active());
|
||||||
if (_blockUntilTransitionDone && scene && scene != GetCurrentScene()) {
|
if (_blockUntilTransitionDone && scene) {
|
||||||
return WaitForTransition(scene, transition);
|
return WaitForTransition(scene, transition);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ void MacroActionScreenshot::CustomScreenshot(OBSWeakSource &source)
|
|||||||
}
|
}
|
||||||
auto s = obs_weak_source_get_source(source);
|
auto s = obs_weak_source_get_source(source);
|
||||||
_screenshot.~ScreenshotHelper();
|
_screenshot.~ScreenshotHelper();
|
||||||
new (&_screenshot) ScreenshotHelper(s, QRect(), false, 0, true, _path);
|
new (&_screenshot) ScreenshotHelper(s, false, 0, true, _path);
|
||||||
obs_source_release(s);
|
obs_source_release(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -601,17 +601,11 @@ void MacroActionSourceEdit::SetWidgetVisibility()
|
|||||||
_entryData->_settingsInputMethod ==
|
_entryData->_settingsInputMethod ==
|
||||||
MacroActionSource::SettingsInputMethod::
|
MacroActionSource::SettingsInputMethod::
|
||||||
INDIVIDUAL_TEMPVAR);
|
INDIVIDUAL_TEMPVAR);
|
||||||
|
_manualSettingValue->setVisible(
|
||||||
if (_entryData->_action == MacroActionSource::Action::SETTINGS &&
|
_entryData->_action == MacroActionSource::Action::SETTINGS &&
|
||||||
_entryData->_settingsInputMethod ==
|
_entryData->_settingsInputMethod ==
|
||||||
MacroActionSource::SettingsInputMethod::INDIVIDUAL_MANUAL) {
|
MacroActionSource::SettingsInputMethod::
|
||||||
RemoveStretchIfPresent(_settingsLayout);
|
INDIVIDUAL_MANUAL);
|
||||||
_manualSettingValue->show();
|
|
||||||
} else {
|
|
||||||
AddStretchIfNecessary(_settingsLayout);
|
|
||||||
_manualSettingValue->hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool showWarning =
|
const bool showWarning =
|
||||||
_entryData->_action == MacroActionSource::Action::ENABLE ||
|
_entryData->_action == MacroActionSource::Action::ENABLE ||
|
||||||
_entryData->_action == MacroActionSource::Action::DISABLE;
|
_entryData->_action == MacroActionSource::Action::DISABLE;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "macro-action-variable.hpp"
|
#include "macro-action-variable.hpp"
|
||||||
#include "macro-condition-edit.hpp"
|
#include "macro-condition-edit.hpp"
|
||||||
|
#include "switcher-data.hpp"
|
||||||
#include "advanced-scene-switcher.hpp"
|
#include "advanced-scene-switcher.hpp"
|
||||||
#include "macro.hpp"
|
#include "macro.hpp"
|
||||||
#include "math-helpers.hpp"
|
#include "math-helpers.hpp"
|
||||||
@@ -50,8 +51,6 @@ const static std::map<MacroActionVariable::Type, std::string> actionTypes = {
|
|||||||
"AdvSceneSwitcher.action.variable.type.extractJson"},
|
"AdvSceneSwitcher.action.variable.type.extractJson"},
|
||||||
{MacroActionVariable::Type::SET_TO_TEMPVAR,
|
{MacroActionVariable::Type::SET_TO_TEMPVAR,
|
||||||
"AdvSceneSwitcher.action.variable.type.setToTempvar"},
|
"AdvSceneSwitcher.action.variable.type.setToTempvar"},
|
||||||
{MacroActionVariable::Type::SCENE_ITEM_NAME,
|
|
||||||
"AdvSceneSwitcher.action.variable.type.sceneItemName"},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void apppend(Variable &var, const std::string &value)
|
static void apppend(Variable &var, const std::string &value)
|
||||||
@@ -135,49 +134,6 @@ void MacroActionVariable::HandleMathExpression(Variable *var)
|
|||||||
var->SetValue(std::get<double>(result));
|
var->SetValue(std::get<double>(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct GetSceneItemNameHelper {
|
|
||||||
int curIdx = 0;
|
|
||||||
int targetIdx = 0;
|
|
||||||
std::string name = "";
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool getSceneItemAtIdx(obs_scene_t *, obs_sceneitem_t *item, void *ptr)
|
|
||||||
{
|
|
||||||
auto data = reinterpret_cast<GetSceneItemNameHelper *>(ptr);
|
|
||||||
if (obs_sceneitem_is_group(item)) {
|
|
||||||
obs_scene_t *scene = obs_sceneitem_group_get_scene(item);
|
|
||||||
obs_scene_enum_items(scene, getSceneItemAtIdx, ptr);
|
|
||||||
}
|
|
||||||
if (data->curIdx == data->targetIdx) {
|
|
||||||
data->name =
|
|
||||||
obs_source_get_name(obs_sceneitem_get_source(item));
|
|
||||||
data->curIdx--;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
data->curIdx--;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroActionVariable::SetToSceneItemName(Variable *var)
|
|
||||||
{
|
|
||||||
auto weakSource = _scene.GetScene();
|
|
||||||
if (!weakSource) {
|
|
||||||
var->SetValue("");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto index = _sceneItemIndex.GetValue();
|
|
||||||
if (index < 1) {
|
|
||||||
var->SetValue("");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto sceneItemCount = GetSceneItemCount(weakSource);
|
|
||||||
OBSSourceAutoRelease source = obs_weak_source_get_source(weakSource);
|
|
||||||
auto scene = obs_scene_from_source(source);
|
|
||||||
GetSceneItemNameHelper data{sceneItemCount, index};
|
|
||||||
obs_scene_enum_items(scene, getSceneItemAtIdx, &data);
|
|
||||||
var->SetValue(data.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct AskForInputParams {
|
struct AskForInputParams {
|
||||||
QString prompt;
|
QString prompt;
|
||||||
QString placeholder;
|
QString placeholder;
|
||||||
@@ -312,9 +268,6 @@ bool MacroActionVariable::PerformAction()
|
|||||||
var->SetValue(*value);
|
var->SetValue(*value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case Type::SCENE_ITEM_NAME:
|
|
||||||
SetToSceneItemName(var.get());
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -346,7 +299,6 @@ bool MacroActionVariable::Save(obs_data_t *obj) const
|
|||||||
_envVariableName.Save(obj, "environmentVariableName");
|
_envVariableName.Save(obj, "environmentVariableName");
|
||||||
_scene.Save(obj);
|
_scene.Save(obj);
|
||||||
_tempVar.Save(obj);
|
_tempVar.Save(obj);
|
||||||
_sceneItemIndex.Save(obj, "sceneItemIndex");
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,7 +328,6 @@ bool MacroActionVariable::Load(obs_data_t *obj)
|
|||||||
_envVariableName.Load(obj, "environmentVariableName");
|
_envVariableName.Load(obj, "environmentVariableName");
|
||||||
_scene.Load(obj);
|
_scene.Load(obj);
|
||||||
_tempVar.Load(obj, GetMacro());
|
_tempVar.Load(obj, GetMacro());
|
||||||
_sceneItemIndex.Load(obj, "sceneItemIndex");
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -506,8 +457,7 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
|||||||
_envVariable(new VariableLineEdit(this)),
|
_envVariable(new VariableLineEdit(this)),
|
||||||
_scenes(new SceneSelectionWidget(this, true, false, true, true,
|
_scenes(new SceneSelectionWidget(this, true, false, true, true,
|
||||||
true)),
|
true)),
|
||||||
_tempVars(new TempVariableSelection(this)),
|
_tempVars(new TempVariableSelection(this))
|
||||||
_sceneItemIndex(new VariableSpinBox())
|
|
||||||
{
|
{
|
||||||
_numValue->setMinimum(-9999999999);
|
_numValue->setMinimum(-9999999999);
|
||||||
_numValue->setMaximum(9999999999);
|
_numValue->setMaximum(9999999999);
|
||||||
@@ -525,7 +475,6 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
|||||||
_regexMatchIdx->setSuffix(".");
|
_regexMatchIdx->setSuffix(".");
|
||||||
_inputPrompt->setSizePolicy(QSizePolicy::MinimumExpanding,
|
_inputPrompt->setSizePolicy(QSizePolicy::MinimumExpanding,
|
||||||
QSizePolicy::Preferred);
|
QSizePolicy::Preferred);
|
||||||
_sceneItemIndex->setMinimum(1);
|
|
||||||
populateTypeSelection(_actions);
|
populateTypeSelection(_actions);
|
||||||
|
|
||||||
QWidget::connect(_variables, SIGNAL(SelectionChanged(const QString &)),
|
QWidget::connect(_variables, SIGNAL(SelectionChanged(const QString &)),
|
||||||
@@ -574,10 +523,6 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
|||||||
QWidget::connect(_tempVars,
|
QWidget::connect(_tempVars,
|
||||||
SIGNAL(SelectionChanged(const TempVariableRef &)),
|
SIGNAL(SelectionChanged(const TempVariableRef &)),
|
||||||
this, SLOT(SelectionChanged(const TempVariableRef &)));
|
this, SLOT(SelectionChanged(const TempVariableRef &)));
|
||||||
QWidget::connect(
|
|
||||||
_sceneItemIndex,
|
|
||||||
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
|
|
||||||
this, SLOT(SceneItemIndexChanged(const NumberVariable<int> &)));
|
|
||||||
|
|
||||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
{"{{variables}}", _variables},
|
{"{{variables}}", _variables},
|
||||||
@@ -599,7 +544,6 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
|||||||
{"{{envVariableName}}", _envVariable},
|
{"{{envVariableName}}", _envVariable},
|
||||||
{"{{scenes}}", _scenes},
|
{"{{scenes}}", _scenes},
|
||||||
{"{{tempVars}}", _tempVars},
|
{"{{tempVars}}", _tempVars},
|
||||||
{"{{sceneItemIndex}}", _sceneItemIndex},
|
|
||||||
};
|
};
|
||||||
auto entryLayout = new QHBoxLayout;
|
auto entryLayout = new QHBoxLayout;
|
||||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.variable.entry"),
|
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.variable.entry"),
|
||||||
@@ -694,7 +638,6 @@ void MacroActionVariableEdit::UpdateEntryData()
|
|||||||
_envVariable->setText(_entryData->_envVariableName);
|
_envVariable->setText(_entryData->_envVariableName);
|
||||||
_scenes->SetScene(_entryData->_scene);
|
_scenes->SetScene(_entryData->_scene);
|
||||||
_tempVars->SetVariable(_entryData->_tempVar);
|
_tempVars->SetVariable(_entryData->_tempVar);
|
||||||
_sceneItemIndex->SetValue(_entryData->_sceneItemIndex);
|
|
||||||
SetWidgetVisibility();
|
SetWidgetVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1039,17 +982,6 @@ void MacroActionVariableEdit::SelectionChanged(const TempVariableRef &var)
|
|||||||
_entryData->_tempVar = var;
|
_entryData->_tempVar = var;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroActionVariableEdit::SceneItemIndexChanged(
|
|
||||||
const NumberVariable<int> &value)
|
|
||||||
{
|
|
||||||
if (_loading || !_entryData) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto lock = LockContext();
|
|
||||||
_entryData->_sceneItemIndex = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroActionVariableEdit::SetWidgetVisibility()
|
void MacroActionVariableEdit::SetWidgetVisibility()
|
||||||
{
|
{
|
||||||
if (!_entryData) {
|
if (!_entryData) {
|
||||||
@@ -1126,15 +1058,10 @@ void MacroActionVariableEdit::SetWidgetVisibility()
|
|||||||
}
|
}
|
||||||
_envVariable->setVisible(_entryData->_type ==
|
_envVariable->setVisible(_entryData->_type ==
|
||||||
MacroActionVariable::Type::ENV_VARIABLE);
|
MacroActionVariable::Type::ENV_VARIABLE);
|
||||||
_scenes->setVisible(
|
_scenes->setVisible(_entryData->_type ==
|
||||||
_entryData->_type ==
|
MacroActionVariable::Type::SCENE_ITEM_COUNT);
|
||||||
MacroActionVariable::Type::SCENE_ITEM_COUNT ||
|
|
||||||
_entryData->_type ==
|
|
||||||
MacroActionVariable::Type::SCENE_ITEM_NAME);
|
|
||||||
_tempVars->setVisible(_entryData->_type ==
|
_tempVars->setVisible(_entryData->_type ==
|
||||||
MacroActionVariable::Type::SET_TO_TEMPVAR);
|
MacroActionVariable::Type::SET_TO_TEMPVAR);
|
||||||
_sceneItemIndex->setVisible(_entryData->_type ==
|
|
||||||
MacroActionVariable::Type::SCENE_ITEM_NAME);
|
|
||||||
adjustSize();
|
adjustSize();
|
||||||
updateGeometry();
|
updateGeometry();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
#include "scene-selection.hpp"
|
#include "scene-selection.hpp"
|
||||||
#include "variable-line-edit.hpp"
|
#include "variable-line-edit.hpp"
|
||||||
#include "variable-text-edit.hpp"
|
#include "variable-text-edit.hpp"
|
||||||
#include "variable-spinbox.hpp"
|
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
@@ -45,7 +44,6 @@ public:
|
|||||||
STRING_LENGTH,
|
STRING_LENGTH,
|
||||||
EXTRACT_JSON,
|
EXTRACT_JSON,
|
||||||
SET_TO_TEMPVAR,
|
SET_TO_TEMPVAR,
|
||||||
SCENE_ITEM_NAME,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Type _type = Type::SET_FIXED_VALUE;
|
Type _type = Type::SET_FIXED_VALUE;
|
||||||
@@ -77,7 +75,6 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
SceneSelection _scene;
|
SceneSelection _scene;
|
||||||
TempVariableRef _tempVar;
|
TempVariableRef _tempVar;
|
||||||
IntVariable _sceneItemIndex = 1;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void DecrementCurrentSegmentVariableRef();
|
void DecrementCurrentSegmentVariableRef();
|
||||||
@@ -85,7 +82,6 @@ private:
|
|||||||
void HandleRegexSubString(Variable *);
|
void HandleRegexSubString(Variable *);
|
||||||
void HandleFindAndReplace(Variable *);
|
void HandleFindAndReplace(Variable *);
|
||||||
void HandleMathExpression(Variable *);
|
void HandleMathExpression(Variable *);
|
||||||
void SetToSceneItemName(Variable *);
|
|
||||||
|
|
||||||
std::weak_ptr<MacroSegment> _macroSegment;
|
std::weak_ptr<MacroSegment> _macroSegment;
|
||||||
int _segmentIdxLoadValue = -1;
|
int _segmentIdxLoadValue = -1;
|
||||||
@@ -133,7 +129,6 @@ private slots:
|
|||||||
void EnvVariableChanged();
|
void EnvVariableChanged();
|
||||||
void SceneChanged(const SceneSelection &);
|
void SceneChanged(const SceneSelection &);
|
||||||
void SelectionChanged(const TempVariableRef &var);
|
void SelectionChanged(const TempVariableRef &var);
|
||||||
void SceneItemIndexChanged(const NumberVariable<int> &);
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void HeaderInfoChanged(const QString &);
|
void HeaderInfoChanged(const QString &);
|
||||||
@@ -172,7 +167,6 @@ private:
|
|||||||
VariableLineEdit *_envVariable;
|
VariableLineEdit *_envVariable;
|
||||||
SceneSelectionWidget *_scenes;
|
SceneSelectionWidget *_scenes;
|
||||||
TempVariableSelection *_tempVars;
|
TempVariableSelection *_tempVars;
|
||||||
VariableSpinBox *_sceneItemIndex;
|
|
||||||
|
|
||||||
std::shared_ptr<MacroActionVariable> _entryData;
|
std::shared_ptr<MacroActionVariable> _entryData;
|
||||||
QTimer _timer;
|
QTimer _timer;
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
#include "macro-action-wait.hpp"
|
#include "macro-action-wait.hpp"
|
||||||
#include "macro-helpers.hpp"
|
#include "switcher-data.hpp"
|
||||||
#include "macro.hpp"
|
|
||||||
#include "sync-helpers.hpp"
|
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
|
|
||||||
#include <random>
|
#include <random>
|
||||||
@@ -26,8 +24,8 @@ static std::default_random_engine re(rd());
|
|||||||
static void waitHelper(std::unique_lock<std::mutex> *lock, Macro *macro,
|
static void waitHelper(std::unique_lock<std::mutex> *lock, Macro *macro,
|
||||||
std::chrono::high_resolution_clock::time_point &time)
|
std::chrono::high_resolution_clock::time_point &time)
|
||||||
{
|
{
|
||||||
while (!MacroWaitShouldAbort() && !macro->GetStop()) {
|
while (!switcher->abortMacroWait && !macro->GetStop()) {
|
||||||
if (GetMacroWaitCV().wait_until(*lock, time) ==
|
if (switcher->macroWaitCv.wait_until(*lock, time) ==
|
||||||
std::cv_status::timeout) {
|
std::cv_status::timeout) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -55,11 +53,11 @@ bool MacroActionWait::PerformAction()
|
|||||||
auto time = std::chrono::high_resolution_clock::now() +
|
auto time = std::chrono::high_resolution_clock::now() +
|
||||||
std::chrono::milliseconds((int)(sleepDuration * 1000));
|
std::chrono::milliseconds((int)(sleepDuration * 1000));
|
||||||
|
|
||||||
SetMacroAbortWait(false);
|
switcher->abortMacroWait = false;
|
||||||
std::unique_lock<std::mutex> lock(*GetMutex());
|
std::unique_lock<std::mutex> lock(switcher->m);
|
||||||
waitHelper(&lock, GetMacro(), time);
|
waitHelper(&lock, GetMacro(), time);
|
||||||
|
|
||||||
return !MacroWaitShouldAbort();
|
return !switcher->abortMacroWait;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroActionWait::Save(obs_data_t *obj) const
|
bool MacroActionWait::Save(obs_data_t *obj) const
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ void MacroActionWebsocketEdit::CheckForSettingsConflict()
|
|||||||
updateGeometry();
|
updateGeometry();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroActionWebsocketEdit::SetWidgetVisibility()
|
void MacroActionWebsocketEdit::SetupWidgetVisibility()
|
||||||
{
|
{
|
||||||
_messageType->setVisible(_entryData->_api ==
|
_messageType->setVisible(_entryData->_api ==
|
||||||
MacroActionWebsocket::API::SCENE_SWITCHER);
|
MacroActionWebsocket::API::SCENE_SWITCHER);
|
||||||
@@ -283,7 +283,7 @@ void MacroActionWebsocketEdit::UpdateEntryData()
|
|||||||
_message->setPlainText(_entryData->_message);
|
_message->setPlainText(_entryData->_message);
|
||||||
_connection->SetConnection(_entryData->_connection);
|
_connection->SetConnection(_entryData->_connection);
|
||||||
|
|
||||||
SetWidgetVisibility();
|
SetupWidgetVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroActionWebsocketEdit::APITypeChanged(int index)
|
void MacroActionWebsocketEdit::APITypeChanged(int index)
|
||||||
@@ -294,7 +294,7 @@ void MacroActionWebsocketEdit::APITypeChanged(int index)
|
|||||||
|
|
||||||
auto lock = LockContext();
|
auto lock = LockContext();
|
||||||
_entryData->_api = static_cast<MacroActionWebsocket::API>(index);
|
_entryData->_api = static_cast<MacroActionWebsocket::API>(index);
|
||||||
SetWidgetVisibility();
|
SetupWidgetVisibility();
|
||||||
emit HeaderInfoChanged(
|
emit HeaderInfoChanged(
|
||||||
QString::fromStdString(_entryData->GetShortDesc()));
|
QString::fromStdString(_entryData->GetShortDesc()));
|
||||||
}
|
}
|
||||||
@@ -308,7 +308,7 @@ void MacroActionWebsocketEdit::MessageTypeChanged(int index)
|
|||||||
auto lock = LockContext();
|
auto lock = LockContext();
|
||||||
_entryData->_type =
|
_entryData->_type =
|
||||||
static_cast<MacroActionWebsocket::MessageType>(index);
|
static_cast<MacroActionWebsocket::MessageType>(index);
|
||||||
SetWidgetVisibility();
|
SetupWidgetVisibility();
|
||||||
emit HeaderInfoChanged(
|
emit HeaderInfoChanged(
|
||||||
QString::fromStdString(_entryData->GetShortDesc()));
|
QString::fromStdString(_entryData->GetShortDesc()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void CheckForSettingsConflict();
|
void CheckForSettingsConflict();
|
||||||
void SetWidgetVisibility();
|
void SetupWidgetVisibility();
|
||||||
void SetupRequestEdit();
|
void SetupRequestEdit();
|
||||||
void SetupEventEdit();
|
void SetupEventEdit();
|
||||||
void SetupGenericEdit();
|
void SetupGenericEdit();
|
||||||
|
|||||||
@@ -62,17 +62,17 @@ MacroConditionAudio::~MacroConditionAudio()
|
|||||||
bool MacroConditionAudio::CheckOutputCondition()
|
bool MacroConditionAudio::CheckOutputCondition()
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
OBSSourceAutoRelease source =
|
auto s = obs_weak_source_get_source(_audioSource.GetSource());
|
||||||
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 && source;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroConditionAudio::CheckVolumeCondition()
|
bool MacroConditionAudio::CheckVolumeCondition()
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
OBSSourceAutoRelease source =
|
auto s = obs_weak_source_get_source(_audioSource.GetSource());
|
||||||
obs_weak_source_get_source(_audioSource.GetSource());
|
|
||||||
|
|
||||||
float curVolume = obs_source_get_volume(source);
|
float curVolume = obs_source_get_volume(s);
|
||||||
bool muted = obs_source_muted(source);
|
bool muted = obs_source_muted(s);
|
||||||
|
|
||||||
switch (_volumeCondition) {
|
switch (_volumeCondition) {
|
||||||
case VolumeCondition::ABOVE:
|
case VolumeCondition::ABOVE:
|
||||||
@@ -126,9 +126,10 @@ bool MacroConditionAudio::CheckVolumeCondition()
|
|||||||
}
|
}
|
||||||
|
|
||||||
SetTempVarValue("configured_volume", std::to_string(curVolume));
|
SetTempVarValue("configured_volume", std::to_string(curVolume));
|
||||||
SetTempVarValue("muted", (source && muted) ? "true" : "false");
|
SetTempVarValue("muted", muted ? "true" : "false");
|
||||||
|
|
||||||
return ret && source;
|
obs_source_release(s);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroConditionAudio::CheckSyncOffset()
|
bool MacroConditionAudio::CheckSyncOffset()
|
||||||
@@ -138,9 +139,8 @@ bool MacroConditionAudio::CheckSyncOffset()
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
OBSSourceAutoRelease source =
|
auto s = obs_weak_source_get_source(_audioSource.GetSource());
|
||||||
obs_weak_source_get_source(_audioSource.GetSource());
|
auto curOffset = obs_source_get_sync_offset(s) / nsPerMs;
|
||||||
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,7 +148,8 @@ 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));
|
||||||
return ret && source;
|
obs_source_release(s);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroConditionAudio::CheckMonitor()
|
bool MacroConditionAudio::CheckMonitor()
|
||||||
@@ -158,13 +159,13 @@ bool MacroConditionAudio::CheckMonitor()
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
OBSSourceAutoRelease source =
|
auto s = obs_weak_source_get_source(_audioSource.GetSource());
|
||||||
obs_weak_source_get_source(_audioSource.GetSource());
|
ret = obs_source_get_monitoring_type(s) == _monitorType;
|
||||||
ret = obs_source_get_monitoring_type(source) == _monitorType;
|
|
||||||
SetVariableValue("");
|
SetVariableValue("");
|
||||||
SetTempVarValue("monitor",
|
SetTempVarValue("monitor",
|
||||||
std::to_string(obs_source_get_monitoring_type(source)));
|
std::to_string(obs_source_get_monitoring_type(s)));
|
||||||
return ret && source;
|
obs_source_release(s);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroConditionAudio::CheckBalance()
|
bool MacroConditionAudio::CheckBalance()
|
||||||
@@ -174,9 +175,8 @@ bool MacroConditionAudio::CheckBalance()
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
OBSSourceAutoRelease source =
|
auto s = obs_weak_source_get_source(_audioSource.GetSource());
|
||||||
obs_weak_source_get_source(_audioSource.GetSource());
|
auto curBalance = obs_source_get_balance_value(s);
|
||||||
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,7 +184,8 @@ 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));
|
||||||
return ret && source;
|
obs_source_release(s);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroConditionAudio::CheckCondition()
|
bool MacroConditionAudio::CheckCondition()
|
||||||
@@ -238,12 +239,13 @@ 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);
|
||||||
OBSSourceAutoRelease audioSource = obs_weak_source_get_source(source);
|
obs_source_t *as = obs_weak_source_get_source(source);
|
||||||
if (!obs_volmeter_attach_source(volmeter, audioSource)) {
|
if (!obs_volmeter_attach_source(volmeter, as)) {
|
||||||
const char *name = obs_source_get_name(audioSource);
|
const char *name = obs_source_get_name(as);
|
||||||
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;
|
||||||
}
|
}
|
||||||
@@ -453,9 +455,10 @@ MacroConditionAudioEdit::MacroConditionAudioEdit(
|
|||||||
void MacroConditionAudioEdit::UpdateVolmeterSource()
|
void MacroConditionAudioEdit::UpdateVolmeterSource()
|
||||||
{
|
{
|
||||||
delete _volMeter;
|
delete _volMeter;
|
||||||
OBSSourceAutoRelease soruce = obs_weak_source_get_source(
|
obs_source_t *soruce = obs_weak_source_get_source(
|
||||||
_entryData->_audioSource.GetSource());
|
_entryData->_audioSource.GetSource());
|
||||||
_volMeter = new VolControl(soruce.Get());
|
_volMeter = new VolControl(soruce);
|
||||||
|
obs_source_release(soruce);
|
||||||
|
|
||||||
QLayout *layout = this->layout();
|
QLayout *layout = this->layout();
|
||||||
layout->addWidget(_volMeter);
|
layout->addWidget(_volMeter);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "macro-condition-cursor.hpp"
|
#include "macro-condition-cursor.hpp"
|
||||||
|
#include "switcher-data.hpp"
|
||||||
#include "platform-funcs.hpp"
|
#include "platform-funcs.hpp"
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
|
|
||||||
@@ -60,15 +61,13 @@ bool MacroConditionCursor::CheckCondition()
|
|||||||
std::to_string(cursorPos.second));
|
std::to_string(cursorPos.second));
|
||||||
break;
|
break;
|
||||||
case Condition::MOVING:
|
case Condition::MOVING:
|
||||||
ret = cursorPos.first != _lastCursorPosition.first ||
|
ret = switcher->cursorPosChanged;
|
||||||
cursorPos.second != _lastCursorPosition.second;
|
|
||||||
break;
|
break;
|
||||||
case Condition::CLICK:
|
case Condition::CLICK:
|
||||||
ret = CheckClick();
|
ret = CheckClick();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_lastCheckTime = std::chrono::high_resolution_clock::now();
|
_lastCheckTime = std::chrono::high_resolution_clock::now();
|
||||||
_lastCursorPosition = cursorPos;
|
|
||||||
|
|
||||||
if (GetVariableValue().empty()) {
|
if (GetVariableValue().empty()) {
|
||||||
SetVariableValue(ret ? "true" : "false");
|
SetVariableValue(ret ? "true" : "false");
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
bool CheckClick();
|
bool CheckClick();
|
||||||
std::chrono::high_resolution_clock::time_point _lastCheckTime{};
|
std::chrono::high_resolution_clock::time_point _lastCheckTime{};
|
||||||
std::pair<int, int> _lastCursorPosition;
|
|
||||||
|
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
static const std::string id;
|
static const std::string id;
|
||||||
|
|||||||
@@ -638,24 +638,10 @@ void MacroConditionDateEdit::AdvancedSettingsToggleClicked()
|
|||||||
{
|
{
|
||||||
auto lock = LockContext();
|
auto lock = LockContext();
|
||||||
_entryData->_dayOfWeekCheck = !_entryData->_dayOfWeekCheck;
|
_entryData->_dayOfWeekCheck = !_entryData->_dayOfWeekCheck;
|
||||||
|
_entryData->_condition = MacroConditionDate::Condition::AT;
|
||||||
}
|
}
|
||||||
|
_condition->setCurrentIndex(0);
|
||||||
switch (_entryData->_condition) {
|
_weekCondition->setCurrentIndex(0);
|
||||||
case MacroConditionDate::Condition::BETWEEN:
|
|
||||||
case MacroConditionDate::Condition::PATTERN:
|
|
||||||
_condition->setCurrentIndex(0);
|
|
||||||
_weekCondition->setCurrentIndex(0);
|
|
||||||
break;
|
|
||||||
case MacroConditionDate::Condition::AT:
|
|
||||||
case MacroConditionDate::Condition::AFTER:
|
|
||||||
case MacroConditionDate::Condition::BEFORE:
|
|
||||||
_weekCondition->setCurrentIndex(
|
|
||||||
static_cast<int>(_entryData->_condition));
|
|
||||||
_condition->setCurrentIndex(
|
|
||||||
static_cast<int>(_entryData->_condition));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
SetWidgetStatus();
|
SetWidgetStatus();
|
||||||
emit HeaderInfoChanged(
|
emit HeaderInfoChanged(
|
||||||
QString::fromStdString(_entryData->GetShortDesc()));
|
QString::fromStdString(_entryData->GetShortDesc()));
|
||||||
|
|||||||
@@ -1,24 +1,84 @@
|
|||||||
#include "macro-condition-edit.hpp"
|
|
||||||
#include "macro.hpp"
|
|
||||||
#include "macro-properties.hpp"
|
|
||||||
#include "advanced-scene-switcher.hpp"
|
#include "advanced-scene-switcher.hpp"
|
||||||
|
#include "switcher-data.hpp"
|
||||||
|
#include "macro-condition-edit.hpp"
|
||||||
#include "macro-condition-scene.hpp"
|
#include "macro-condition-scene.hpp"
|
||||||
#include "section.hpp"
|
#include "section.hpp"
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
|
std::map<std::string, MacroConditionInfo> &MacroConditionFactory::GetMap()
|
||||||
|
{
|
||||||
|
static std::map<std::string, MacroConditionInfo> _methods;
|
||||||
|
return _methods;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroConditionFactory::Register(const std::string &id,
|
||||||
|
MacroConditionInfo info)
|
||||||
|
{
|
||||||
|
if (auto it = GetMap().find(id); it == GetMap().end()) {
|
||||||
|
GetMap()[id] = info;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<MacroCondition>
|
||||||
|
MacroConditionFactory::Create(const std::string &id, Macro *m)
|
||||||
|
{
|
||||||
|
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
||||||
|
return it->second._createFunc(m);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget *
|
||||||
|
MacroConditionFactory::CreateWidget(const std::string &id, QWidget *parent,
|
||||||
|
std::shared_ptr<MacroCondition> cond)
|
||||||
|
{
|
||||||
|
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
||||||
|
return it->second._createWidgetFunc(parent, cond);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string MacroConditionFactory::GetConditionName(const std::string &id)
|
||||||
|
{
|
||||||
|
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
||||||
|
return it->second._name;
|
||||||
|
}
|
||||||
|
return "unknown condition";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string MacroConditionFactory::GetIdByName(const QString &name)
|
||||||
|
{
|
||||||
|
for (auto it : GetMap()) {
|
||||||
|
if (name == obs_module_text(it.second._name.c_str())) {
|
||||||
|
return it.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroConditionFactory::UsesDurationModifier(const std::string &id)
|
||||||
|
{
|
||||||
|
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
||||||
|
return it->second._useDurationModifier;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void populateLogicSelection(QComboBox *list, bool root = false)
|
static inline void populateLogicSelection(QComboBox *list, bool root = false)
|
||||||
{
|
{
|
||||||
if (root) {
|
if (root) {
|
||||||
for (const auto &entry : MacroCondition::logicTypes) {
|
for (auto entry : MacroCondition::logicTypes) {
|
||||||
if (static_cast<int>(entry.first) < logic_root_offset) {
|
if (static_cast<int>(entry.first) < logic_root_offset) {
|
||||||
list->addItem(obs_module_text(
|
list->addItem(obs_module_text(
|
||||||
entry.second._name.c_str()));
|
entry.second._name.c_str()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (const auto &entry : MacroCondition::logicTypes) {
|
for (auto entry : MacroCondition::logicTypes) {
|
||||||
if (static_cast<int>(entry.first) >=
|
if (static_cast<int>(entry.first) >=
|
||||||
logic_root_offset) {
|
logic_root_offset) {
|
||||||
list->addItem(obs_module_text(
|
list->addItem(obs_module_text(
|
||||||
@@ -30,7 +90,7 @@ static inline void populateLogicSelection(QComboBox *list, bool root = false)
|
|||||||
|
|
||||||
static inline void populateConditionSelection(QComboBox *list)
|
static inline void populateConditionSelection(QComboBox *list)
|
||||||
{
|
{
|
||||||
for (const auto &[_, condition] :
|
for (auto &[_, condition] :
|
||||||
MacroConditionFactory::GetConditionTypes()) {
|
MacroConditionFactory::GetConditionTypes()) {
|
||||||
QString entry(obs_module_text(condition._name.c_str()));
|
QString entry(obs_module_text(condition._name.c_str()));
|
||||||
if (list->findText(entry) == -1) {
|
if (list->findText(entry) == -1) {
|
||||||
@@ -119,7 +179,7 @@ void DurationModifierEdit::Collapse(bool collapse)
|
|||||||
MacroConditionEdit::MacroConditionEdit(
|
MacroConditionEdit::MacroConditionEdit(
|
||||||
QWidget *parent, std::shared_ptr<MacroCondition> *entryData,
|
QWidget *parent, std::shared_ptr<MacroCondition> *entryData,
|
||||||
const std::string &id, bool root)
|
const std::string &id, bool root)
|
||||||
: MacroSegmentEdit(GetGlobalMacroProperties()._highlightConditions,
|
: MacroSegmentEdit(switcher->macroProperties._highlightConditions,
|
||||||
parent),
|
parent),
|
||||||
_logicSelection(new QComboBox()),
|
_logicSelection(new QComboBox()),
|
||||||
_conditionSelection(new FilterComboBox()),
|
_conditionSelection(new FilterComboBox()),
|
||||||
|
|||||||
@@ -1,12 +1,38 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "macro-condition.hpp"
|
#include "macro-condition.hpp"
|
||||||
#include "macro-condition-factory.hpp"
|
|
||||||
#include "filter-combo-box.hpp"
|
#include "filter-combo-box.hpp"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
|
struct MacroConditionInfo {
|
||||||
|
using TCreateMethod = std::shared_ptr<MacroCondition> (*)(Macro *m);
|
||||||
|
using TCreateWidgetMethod =
|
||||||
|
QWidget *(*)(QWidget *parent, std::shared_ptr<MacroCondition>);
|
||||||
|
TCreateMethod _createFunc = nullptr;
|
||||||
|
TCreateWidgetMethod _createWidgetFunc = nullptr;
|
||||||
|
std::string _name;
|
||||||
|
bool _useDurationModifier = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MacroConditionFactory {
|
||||||
|
public:
|
||||||
|
MacroConditionFactory() = delete;
|
||||||
|
static bool Register(const std::string &, MacroConditionInfo);
|
||||||
|
static std::shared_ptr<MacroCondition> Create(const std::string &,
|
||||||
|
Macro *m);
|
||||||
|
static QWidget *CreateWidget(const std::string &id, QWidget *parent,
|
||||||
|
std::shared_ptr<MacroCondition>);
|
||||||
|
static auto GetConditionTypes() { return GetMap(); }
|
||||||
|
static std::string GetConditionName(const std::string &);
|
||||||
|
static std::string GetIdByName(const QString &name);
|
||||||
|
static bool UsesDurationModifier(const std::string &id);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static std::map<std::string, MacroConditionInfo> &GetMap();
|
||||||
|
};
|
||||||
|
|
||||||
class DurationModifierEdit : public QWidget {
|
class DurationModifierEdit : public QWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -1,66 +0,0 @@
|
|||||||
#include "macro-condition-factory.hpp"
|
|
||||||
|
|
||||||
namespace advss {
|
|
||||||
|
|
||||||
std::map<std::string, MacroConditionInfo> &MacroConditionFactory::GetMap()
|
|
||||||
{
|
|
||||||
static std::map<std::string, MacroConditionInfo> _methods;
|
|
||||||
return _methods;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MacroConditionFactory::Register(const std::string &id,
|
|
||||||
MacroConditionInfo info)
|
|
||||||
{
|
|
||||||
if (auto it = GetMap().find(id); it == GetMap().end()) {
|
|
||||||
GetMap()[id] = info;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<MacroCondition>
|
|
||||||
MacroConditionFactory::Create(const std::string &id, Macro *m)
|
|
||||||
{
|
|
||||||
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
|
||||||
return it->second._create(m);
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
QWidget *
|
|
||||||
MacroConditionFactory::CreateWidget(const std::string &id, QWidget *parent,
|
|
||||||
std::shared_ptr<MacroCondition> cond)
|
|
||||||
{
|
|
||||||
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
|
||||||
return it->second._createWidget(parent, cond);
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string MacroConditionFactory::GetConditionName(const std::string &id)
|
|
||||||
{
|
|
||||||
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
|
||||||
return it->second._name;
|
|
||||||
}
|
|
||||||
return "unknown condition";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string MacroConditionFactory::GetIdByName(const QString &name)
|
|
||||||
{
|
|
||||||
for (auto it : GetMap()) {
|
|
||||||
if (name == obs_module_text(it.second._name.c_str())) {
|
|
||||||
return it.first;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MacroConditionFactory::UsesDurationModifier(const std::string &id)
|
|
||||||
{
|
|
||||||
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
|
||||||
return it->second._useDurationModifier;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace advss
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "macro-condition.hpp"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace advss {
|
|
||||||
|
|
||||||
struct MacroConditionInfo {
|
|
||||||
using CreateCondition = std::shared_ptr<MacroCondition> (*)(Macro *m);
|
|
||||||
using CreateConditionWidget =
|
|
||||||
QWidget *(*)(QWidget *parent, std::shared_ptr<MacroCondition>);
|
|
||||||
CreateCondition _create = nullptr;
|
|
||||||
CreateConditionWidget _createWidget = nullptr;
|
|
||||||
std::string _name;
|
|
||||||
bool _useDurationModifier = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
class MacroConditionFactory {
|
|
||||||
public:
|
|
||||||
MacroConditionFactory() = delete;
|
|
||||||
static bool Register(const std::string &, MacroConditionInfo);
|
|
||||||
static std::shared_ptr<MacroCondition> Create(const std::string &,
|
|
||||||
Macro *m);
|
|
||||||
static QWidget *CreateWidget(const std::string &id, QWidget *parent,
|
|
||||||
std::shared_ptr<MacroCondition>);
|
|
||||||
static auto GetConditionTypes() { return GetMap(); }
|
|
||||||
static std::string GetConditionName(const std::string &);
|
|
||||||
static std::string GetIdByName(const QString &name);
|
|
||||||
static bool UsesDurationModifier(const std::string &id);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static std::map<std::string, MacroConditionInfo> &GetMap();
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace advss
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#include "macro-condition-file.hpp"
|
#include "macro-condition-file.hpp"
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
|
#include "switcher-data.hpp"
|
||||||
#include "curl-helper.hpp"
|
#include "curl-helper.hpp"
|
||||||
#include "plugin-state-helpers.hpp"
|
|
||||||
|
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
@@ -28,16 +28,16 @@ static size_t WriteCallback(void *contents, size_t size, size_t nmemb,
|
|||||||
static std::string getRemoteData(std::string &url)
|
static std::string getRemoteData(std::string &url)
|
||||||
{
|
{
|
||||||
std::string readBuffer;
|
std::string readBuffer;
|
||||||
CurlHelper::SetOpt(CURLOPT_URL, url.c_str());
|
switcher->curl.SetOpt(CURLOPT_URL, url.c_str());
|
||||||
CurlHelper::SetOpt(CURLOPT_WRITEFUNCTION, WriteCallback);
|
switcher->curl.SetOpt(CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||||
CurlHelper::SetOpt(CURLOPT_WRITEDATA, &readBuffer);
|
switcher->curl.SetOpt(CURLOPT_WRITEDATA, &readBuffer);
|
||||||
// Set timeout to at least one second
|
// Set timeout to at least one second
|
||||||
int timeout = GetIntervalValue() / 1000;
|
int timeout = switcher->interval / 1000;
|
||||||
if (timeout == 0) {
|
if (timeout == 0) {
|
||||||
timeout = 1;
|
timeout = 1;
|
||||||
}
|
}
|
||||||
CurlHelper::SetOpt(CURLOPT_TIMEOUT, 1);
|
switcher->curl.SetOpt(CURLOPT_TIMEOUT, 1);
|
||||||
CurlHelper::Perform();
|
switcher->curl.Perform();
|
||||||
return readBuffer;
|
return readBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,8 +24,6 @@ const static std::map<MacroConditionMacro::Type, std::string>
|
|||||||
"AdvSceneSwitcher.condition.macro.type.actionDisabled"},
|
"AdvSceneSwitcher.condition.macro.type.actionDisabled"},
|
||||||
{MacroConditionMacro::Type::ACTION_ENABLED,
|
{MacroConditionMacro::Type::ACTION_ENABLED,
|
||||||
"AdvSceneSwitcher.condition.macro.type.actionEnabled"},
|
"AdvSceneSwitcher.condition.macro.type.actionEnabled"},
|
||||||
{MacroConditionMacro::Type::PAUSED,
|
|
||||||
"AdvSceneSwitcher.condition.macro.type.paused"},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const static std::map<MacroConditionMacro::CounterCondition, std::string>
|
const static std::map<MacroConditionMacro::CounterCondition, std::string>
|
||||||
@@ -77,8 +75,6 @@ bool MacroConditionMacro::CheckMultiStateCondition()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SetTempVarValue("matchedCount", std::to_string(matchedCount));
|
|
||||||
|
|
||||||
switch (_multiSateCondition) {
|
switch (_multiSateCondition) {
|
||||||
case MacroConditionMacro::MultiStateCondition::BELOW:
|
case MacroConditionMacro::MultiStateCondition::BELOW:
|
||||||
return matchedCount < _multiSateCount;
|
return matchedCount < _multiSateCount;
|
||||||
@@ -111,16 +107,6 @@ bool MacroConditionMacro::CheckActionStateCondition()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroConditionMacro::CheckPauseState()
|
|
||||||
{
|
|
||||||
auto macro = _macro.GetMacro();
|
|
||||||
if (!macro) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return macro->Paused();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MacroConditionMacro::CheckCountCondition()
|
bool MacroConditionMacro::CheckCountCondition()
|
||||||
{
|
{
|
||||||
auto macro = _macro.GetMacro();
|
auto macro = _macro.GetMacro();
|
||||||
@@ -128,8 +114,6 @@ bool MacroConditionMacro::CheckCountCondition()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetTempVarValue("runCount", std::to_string(macro->RunCount()));
|
|
||||||
|
|
||||||
switch (_counterCondition) {
|
switch (_counterCondition) {
|
||||||
case CounterCondition::BELOW:
|
case CounterCondition::BELOW:
|
||||||
return macro->RunCount() < _count;
|
return macro->RunCount() < _count;
|
||||||
@@ -156,8 +140,6 @@ bool MacroConditionMacro::CheckCondition()
|
|||||||
case Type::ACTION_DISABLED:
|
case Type::ACTION_DISABLED:
|
||||||
case Type::ACTION_ENABLED:
|
case Type::ACTION_ENABLED:
|
||||||
return CheckActionStateCondition();
|
return CheckActionStateCondition();
|
||||||
case Type::PAUSED:
|
|
||||||
return CheckPauseState();
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -211,7 +193,7 @@ bool MacroConditionMacro::Load(obs_data_t *obj)
|
|||||||
|
|
||||||
bool MacroConditionMacro::PostLoad()
|
bool MacroConditionMacro::PostLoad()
|
||||||
{
|
{
|
||||||
return MacroCondition::PostLoad() && MacroRefCondition::PostLoad() &&
|
return MacroRefCondition::PostLoad() &&
|
||||||
MultiMacroRefCondtition::PostLoad();
|
MultiMacroRefCondtition::PostLoad();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,45 +202,6 @@ std::string MacroConditionMacro::GetShortDesc() const
|
|||||||
return _macro.Name();
|
return _macro.Name();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionMacro::SetType(Type type)
|
|
||||||
{
|
|
||||||
_type = type;
|
|
||||||
SetupTempVars();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroConditionMacro::SetupTempVars()
|
|
||||||
{
|
|
||||||
MacroCondition::SetupTempVars();
|
|
||||||
switch (_type) {
|
|
||||||
case Type::COUNT:
|
|
||||||
AddTempvar(
|
|
||||||
"runCount",
|
|
||||||
obs_module_text(
|
|
||||||
"AdvSceneSwitcher.tempVar.macro.runCount"),
|
|
||||||
obs_module_text(
|
|
||||||
"AdvSceneSwitcher.tempVar.macro.runCount.description"));
|
|
||||||
break;
|
|
||||||
case Type::STATE:
|
|
||||||
break;
|
|
||||||
case Type::MULTI_STATE:
|
|
||||||
AddTempvar(
|
|
||||||
"matchedCount",
|
|
||||||
obs_module_text(
|
|
||||||
"AdvSceneSwitcher.tempVar.macro.matchedCount"),
|
|
||||||
obs_module_text(
|
|
||||||
"AdvSceneSwitcher.tempVar.macro.matchedCount.description"));
|
|
||||||
break;
|
|
||||||
case Type::ACTION_DISABLED:
|
|
||||||
break;
|
|
||||||
case Type::ACTION_ENABLED:
|
|
||||||
break;
|
|
||||||
case Type::PAUSED:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void populateTypeSelection(QComboBox *list)
|
static inline void populateTypeSelection(QComboBox *list)
|
||||||
{
|
{
|
||||||
for (auto entry : macroConditionTypes) {
|
for (auto entry : macroConditionTypes) {
|
||||||
@@ -392,10 +335,7 @@ void MacroConditionMacroEdit::ClearLayouts()
|
|||||||
|
|
||||||
void MacroConditionMacroEdit::SetupWidgets()
|
void MacroConditionMacroEdit::SetupWidgets()
|
||||||
{
|
{
|
||||||
SetWidgetVisibility();
|
switch (_entryData->_type) {
|
||||||
ClearLayouts();
|
|
||||||
|
|
||||||
switch (_entryData->GetType()) {
|
|
||||||
case MacroConditionMacro::Type::COUNT:
|
case MacroConditionMacro::Type::COUNT:
|
||||||
SetupCountWidgets();
|
SetupCountWidgets();
|
||||||
break;
|
break;
|
||||||
@@ -411,9 +351,6 @@ void MacroConditionMacroEdit::SetupWidgets()
|
|||||||
case MacroConditionMacro::Type::ACTION_ENABLED:
|
case MacroConditionMacro::Type::ACTION_ENABLED:
|
||||||
SetupActionStateWidgets(true);
|
SetupActionStateWidgets(true);
|
||||||
break;
|
break;
|
||||||
case MacroConditionMacro::Type::PAUSED:
|
|
||||||
SetupPauseWidgets();
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -421,24 +358,38 @@ void MacroConditionMacroEdit::SetupWidgets()
|
|||||||
|
|
||||||
void MacroConditionMacroEdit::SetupStateWidgets()
|
void MacroConditionMacroEdit::SetupStateWidgets()
|
||||||
{
|
{
|
||||||
|
SetWidgetVisibility();
|
||||||
|
ClearLayouts();
|
||||||
|
|
||||||
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
|
{"{{macros}}", _macros},
|
||||||
|
};
|
||||||
PlaceWidgets(
|
PlaceWidgets(
|
||||||
obs_module_text("AdvSceneSwitcher.condition.macro.state.entry"),
|
obs_module_text("AdvSceneSwitcher.condition.macro.state.entry"),
|
||||||
_settingsLine1, {{"{{macros}}", _macros}});
|
_settingsLine1, widgetPlaceholders);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionMacroEdit::SetupMultiStateWidgets()
|
void MacroConditionMacroEdit::SetupMultiStateWidgets()
|
||||||
{
|
{
|
||||||
|
SetWidgetVisibility();
|
||||||
|
ClearLayouts();
|
||||||
|
|
||||||
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
|
{"{{multiStateConditions}}", _multiStateConditions},
|
||||||
|
{"{{multiStateCount}}", _multiStateCount},
|
||||||
|
};
|
||||||
PlaceWidgets(
|
PlaceWidgets(
|
||||||
obs_module_text(
|
obs_module_text(
|
||||||
"AdvSceneSwitcher.condition.macro.multistate.entry"),
|
"AdvSceneSwitcher.condition.macro.multistate.entry"),
|
||||||
_settingsLine1,
|
_settingsLine1, widgetPlaceholders);
|
||||||
{{"{{multiStateConditions}}", _multiStateConditions},
|
|
||||||
{"{{multiStateCount}}", _multiStateCount}});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionMacroEdit::SetupCountWidgets()
|
void MacroConditionMacroEdit::SetupCountWidgets()
|
||||||
{
|
{
|
||||||
const std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
SetWidgetVisibility();
|
||||||
|
ClearLayouts();
|
||||||
|
|
||||||
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
{"{{macros}}", _macros},
|
{"{{macros}}", _macros},
|
||||||
{"{{conditions}}", _counterConditions},
|
{"{{conditions}}", _counterConditions},
|
||||||
{"{{count}}", _count},
|
{"{{count}}", _count},
|
||||||
@@ -457,6 +408,9 @@ void MacroConditionMacroEdit::SetupCountWidgets()
|
|||||||
|
|
||||||
void MacroConditionMacroEdit::SetupActionStateWidgets(bool enable)
|
void MacroConditionMacroEdit::SetupActionStateWidgets(bool enable)
|
||||||
{
|
{
|
||||||
|
SetWidgetVisibility();
|
||||||
|
ClearLayouts();
|
||||||
|
|
||||||
PlaceWidgets(
|
PlaceWidgets(
|
||||||
obs_module_text(
|
obs_module_text(
|
||||||
enable ? "AdvSceneSwitcher.condition.macro.actionState.enabled.entry"
|
enable ? "AdvSceneSwitcher.condition.macro.actionState.enabled.entry"
|
||||||
@@ -465,49 +419,35 @@ void MacroConditionMacroEdit::SetupActionStateWidgets(bool enable)
|
|||||||
{{"{{macros}}", _macros}, {"{{actionIndex}}", _actionIndex}});
|
{{"{{macros}}", _macros}, {"{{actionIndex}}", _actionIndex}});
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionMacroEdit::SetupPauseWidgets()
|
|
||||||
{
|
|
||||||
PlaceWidgets(obs_module_text(
|
|
||||||
"AdvSceneSwitcher.condition.macro.paused.entry"),
|
|
||||||
_settingsLine1, {{"{{macros}}", _macros}});
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroConditionMacroEdit::SetWidgetVisibility()
|
void MacroConditionMacroEdit::SetWidgetVisibility()
|
||||||
{
|
{
|
||||||
_macros->setVisible(
|
_macros->setVisible(
|
||||||
_entryData->GetType() == MacroConditionMacro::Type::COUNT ||
|
_entryData->_type == MacroConditionMacro::Type::COUNT ||
|
||||||
_entryData->GetType() == MacroConditionMacro::Type::STATE ||
|
_entryData->_type == MacroConditionMacro::Type::STATE ||
|
||||||
_entryData->GetType() ==
|
_entryData->_type ==
|
||||||
MacroConditionMacro::Type::ACTION_DISABLED ||
|
MacroConditionMacro::Type::ACTION_DISABLED ||
|
||||||
_entryData->GetType() ==
|
_entryData->_type == MacroConditionMacro::Type::ACTION_ENABLED);
|
||||||
MacroConditionMacro::Type::ACTION_ENABLED ||
|
_counterConditions->setVisible(_entryData->_type ==
|
||||||
_entryData->GetType() == MacroConditionMacro::Type::PAUSED);
|
|
||||||
_counterConditions->setVisible(_entryData->GetType() ==
|
|
||||||
MacroConditionMacro::Type::COUNT);
|
MacroConditionMacro::Type::COUNT);
|
||||||
_count->setVisible(_entryData->GetType() ==
|
_count->setVisible(_entryData->_type ==
|
||||||
MacroConditionMacro::Type::COUNT);
|
MacroConditionMacro::Type::COUNT);
|
||||||
_currentCount->setVisible(_entryData->GetType() ==
|
_currentCount->setVisible(_entryData->_type ==
|
||||||
MacroConditionMacro::Type::COUNT);
|
MacroConditionMacro::Type::COUNT);
|
||||||
_resetCount->setVisible(_entryData->GetType() ==
|
_resetCount->setVisible(_entryData->_type ==
|
||||||
MacroConditionMacro::Type::COUNT);
|
MacroConditionMacro::Type::COUNT);
|
||||||
_macroList->setVisible(_entryData->GetType() ==
|
_macroList->setVisible(_entryData->_type ==
|
||||||
MacroConditionMacro::Type::MULTI_STATE);
|
MacroConditionMacro::Type::MULTI_STATE);
|
||||||
_multiStateConditions->setVisible(
|
_multiStateConditions->setVisible(
|
||||||
_entryData->GetType() ==
|
_entryData->_type == MacroConditionMacro::Type::MULTI_STATE);
|
||||||
MacroConditionMacro::Type::MULTI_STATE);
|
_multiStateCount->setVisible(_entryData->_type ==
|
||||||
_multiStateCount->setVisible(_entryData->GetType() ==
|
|
||||||
MacroConditionMacro::Type::MULTI_STATE);
|
MacroConditionMacro::Type::MULTI_STATE);
|
||||||
_actionIndex->setVisible(
|
_actionIndex->setVisible(
|
||||||
_entryData->GetType() ==
|
_entryData->_type ==
|
||||||
MacroConditionMacro::Type::ACTION_DISABLED ||
|
MacroConditionMacro::Type::ACTION_DISABLED ||
|
||||||
_entryData->GetType() ==
|
_entryData->_type == MacroConditionMacro::Type::ACTION_ENABLED);
|
||||||
MacroConditionMacro::Type::ACTION_ENABLED);
|
if (_entryData->_type == MacroConditionMacro::Type::MULTI_STATE ||
|
||||||
if (_entryData->GetType() == MacroConditionMacro::Type::MULTI_STATE ||
|
_entryData->_type == MacroConditionMacro::Type::ACTION_DISABLED ||
|
||||||
_entryData->GetType() ==
|
_entryData->_type == MacroConditionMacro::Type::ACTION_ENABLED) {
|
||||||
MacroConditionMacro::Type::ACTION_DISABLED ||
|
|
||||||
_entryData->GetType() ==
|
|
||||||
MacroConditionMacro::Type::ACTION_ENABLED ||
|
|
||||||
_entryData->GetType() == MacroConditionMacro::Type::PAUSED) {
|
|
||||||
_pausedWarning->hide();
|
_pausedWarning->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -523,7 +463,7 @@ void MacroConditionMacroEdit::UpdateEntryData()
|
|||||||
|
|
||||||
SetupWidgets();
|
SetupWidgets();
|
||||||
_macros->SetCurrentMacro(_entryData->_macro);
|
_macros->SetCurrentMacro(_entryData->_macro);
|
||||||
_types->setCurrentIndex(static_cast<int>(_entryData->GetType()));
|
_types->setCurrentIndex(static_cast<int>(_entryData->_type));
|
||||||
_counterConditions->setCurrentIndex(
|
_counterConditions->setCurrentIndex(
|
||||||
static_cast<int>(_entryData->_counterCondition));
|
static_cast<int>(_entryData->_counterCondition));
|
||||||
_count->SetValue(_entryData->_count);
|
_count->SetValue(_entryData->_count);
|
||||||
@@ -595,7 +535,7 @@ void MacroConditionMacroEdit::TypeChanged(int type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto lock = LockContext();
|
auto lock = LockContext();
|
||||||
_entryData->SetType(static_cast<MacroConditionMacro::Type>(type));
|
_entryData->_type = static_cast<MacroConditionMacro::Type>(type);
|
||||||
SetupWidgets();
|
SetupWidgets();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -631,8 +571,7 @@ void MacroConditionMacroEdit::UpdatePaused()
|
|||||||
auto macro = _entryData->_macro.GetMacro();
|
auto macro = _entryData->_macro.GetMacro();
|
||||||
_pausedWarning->setVisible(
|
_pausedWarning->setVisible(
|
||||||
_entryData &&
|
_entryData &&
|
||||||
_entryData->GetType() !=
|
_entryData->_type != MacroConditionMacro::Type::MULTI_STATE &&
|
||||||
MacroConditionMacro::Type::MULTI_STATE &&
|
|
||||||
macro && macro->Paused());
|
macro && macro->Paused());
|
||||||
adjustSize();
|
adjustSize();
|
||||||
updateGeometry();
|
updateGeometry();
|
||||||
|
|||||||
@@ -39,10 +39,8 @@ public:
|
|||||||
MULTI_STATE,
|
MULTI_STATE,
|
||||||
ACTION_DISABLED,
|
ACTION_DISABLED,
|
||||||
ACTION_ENABLED,
|
ACTION_ENABLED,
|
||||||
PAUSED,
|
|
||||||
};
|
};
|
||||||
void SetType(Type);
|
Type _type = Type::STATE;
|
||||||
Type GetType() const { return _type; }
|
|
||||||
|
|
||||||
enum class CounterCondition {
|
enum class CounterCondition {
|
||||||
BELOW,
|
BELOW,
|
||||||
@@ -66,11 +64,7 @@ private:
|
|||||||
bool CheckStateCondition();
|
bool CheckStateCondition();
|
||||||
bool CheckMultiStateCondition();
|
bool CheckMultiStateCondition();
|
||||||
bool CheckActionStateCondition();
|
bool CheckActionStateCondition();
|
||||||
bool CheckPauseState();
|
|
||||||
|
|
||||||
void SetupTempVars();
|
|
||||||
|
|
||||||
Type _type = Type::STATE;
|
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
static const std::string id;
|
static const std::string id;
|
||||||
};
|
};
|
||||||
@@ -134,7 +128,6 @@ private:
|
|||||||
void SetupMultiStateWidgets();
|
void SetupMultiStateWidgets();
|
||||||
void SetupCountWidgets();
|
void SetupCountWidgets();
|
||||||
void SetupActionStateWidgets(bool enable);
|
void SetupActionStateWidgets(bool enable);
|
||||||
void SetupPauseWidgets();
|
|
||||||
void SetWidgetVisibility();
|
void SetWidgetVisibility();
|
||||||
bool _loading = true;
|
bool _loading = true;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
#include "macro-condition-media.hpp"
|
#include "macro-condition-media.hpp"
|
||||||
#include "macro.hpp"
|
#include "switcher-data.hpp"
|
||||||
#include "plugin-state-helpers.hpp"
|
|
||||||
#include "scene-switch-helpers.hpp"
|
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
@@ -150,20 +148,26 @@ bool MacroConditionMedia::CheckMediaMatch()
|
|||||||
if (!_source.GetSource()) {
|
if (!_source.GetSource()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
bool match = false;
|
||||||
bool matched = CheckState() && CheckTime();
|
bool matched = CheckState() && CheckTime();
|
||||||
|
|
||||||
|
if (matched && !(_onlyMatchOnChagne && _alreadyMatched)) {
|
||||||
|
match = true;
|
||||||
|
}
|
||||||
|
_alreadyMatched = matched;
|
||||||
|
|
||||||
// reset for next check
|
// reset for next check
|
||||||
_stopped = false;
|
_stopped = false;
|
||||||
_ended = false;
|
_ended = false;
|
||||||
_next = false;
|
_next = false;
|
||||||
|
|
||||||
return matched;
|
return match;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionMedia::HandleSceneChange()
|
void MacroConditionMedia::HandleSceneChange()
|
||||||
{
|
{
|
||||||
UpdateMediaSourcesOfSceneList();
|
UpdateMediaSourcesOfSceneList();
|
||||||
_lastConfigureScene = GetCurrentScene();
|
_lastConfigureScene = switcher->currentScene;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroConditionMedia::CheckCondition()
|
bool MacroConditionMedia::CheckCondition()
|
||||||
@@ -190,7 +194,7 @@ bool MacroConditionMedia::CheckCondition()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_lastConfigureScene != GetCurrentScene()) {
|
if (_lastConfigureScene != switcher->currentScene) {
|
||||||
HandleSceneChange();
|
HandleSceneChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,6 +210,7 @@ bool MacroConditionMedia::Save(obs_data_t *obj) const
|
|||||||
obs_data_set_int(obj, "state", static_cast<int>(_state));
|
obs_data_set_int(obj, "state", static_cast<int>(_state));
|
||||||
obs_data_set_int(obj, "restriction", static_cast<int>(_restriction));
|
obs_data_set_int(obj, "restriction", static_cast<int>(_restriction));
|
||||||
_time.Save(obj);
|
_time.Save(obj);
|
||||||
|
obs_data_set_bool(obj, "matchOnChagne", _onlyMatchOnChagne);
|
||||||
obs_data_set_int(obj, "version", 0);
|
obs_data_set_int(obj, "version", 0);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -263,6 +268,7 @@ bool MacroConditionMedia::Load(obs_data_t *obj)
|
|||||||
_restriction = static_cast<MacroConditionMedia::Time>(
|
_restriction = static_cast<MacroConditionMedia::Time>(
|
||||||
obs_data_get_int(obj, "restriction"));
|
obs_data_get_int(obj, "restriction"));
|
||||||
_time.Load(obj);
|
_time.Load(obj);
|
||||||
|
_onlyMatchOnChagne = obs_data_get_bool(obj, "matchOnChagne");
|
||||||
|
|
||||||
if (_sourceType == Type::SOURCE) {
|
if (_sourceType == Type::SOURCE) {
|
||||||
obs_source_t *mediasource =
|
obs_source_t *mediasource =
|
||||||
@@ -402,7 +408,9 @@ MacroConditionMediaEdit::MacroConditionMediaEdit(
|
|||||||
_sources(new SourceSelectionWidget(this, QStringList(), true)),
|
_sources(new SourceSelectionWidget(this, QStringList(), true)),
|
||||||
_states(new QComboBox()),
|
_states(new QComboBox()),
|
||||||
_timeRestrictions(new QComboBox()),
|
_timeRestrictions(new QComboBox()),
|
||||||
_time(new DurationSelection())
|
_time(new DurationSelection()),
|
||||||
|
_onChange(new QCheckBox(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.condition.media.matchOnChange")))
|
||||||
{
|
{
|
||||||
_states->setToolTip(obs_module_text(
|
_states->setToolTip(obs_module_text(
|
||||||
"AdvSceneSwitcher.condition.media.inconsistencyInfo"));
|
"AdvSceneSwitcher.condition.media.inconsistencyInfo"));
|
||||||
@@ -424,12 +432,14 @@ MacroConditionMediaEdit::MacroConditionMediaEdit(
|
|||||||
this, SLOT(TimeRestrictionChanged(int)));
|
this, SLOT(TimeRestrictionChanged(int)));
|
||||||
QWidget::connect(_time, SIGNAL(DurationChanged(const Duration &)), this,
|
QWidget::connect(_time, SIGNAL(DurationChanged(const Duration &)), this,
|
||||||
SLOT(TimeChanged(const Duration &)));
|
SLOT(TimeChanged(const Duration &)));
|
||||||
|
QWidget::connect(_onChange, SIGNAL(stateChanged(int)), this,
|
||||||
|
SLOT(OnChangeChanged(int)));
|
||||||
|
|
||||||
populateSourceTypes(_sourceTypes);
|
populateSourceTypes(_sourceTypes);
|
||||||
populateMediaStates(_states);
|
populateMediaStates(_states);
|
||||||
populateMediaTimes(_timeRestrictions);
|
populateMediaTimes(_timeRestrictions);
|
||||||
|
|
||||||
auto layout = new QHBoxLayout;
|
QHBoxLayout *entryLayout = new QHBoxLayout;
|
||||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
{"{{sourceTypes}}", _sourceTypes},
|
{"{{sourceTypes}}", _sourceTypes},
|
||||||
{"{{mediaSources}}", _sources},
|
{"{{mediaSources}}", _sources},
|
||||||
@@ -439,8 +449,11 @@ MacroConditionMediaEdit::MacroConditionMediaEdit(
|
|||||||
{"{{time}}", _time},
|
{"{{time}}", _time},
|
||||||
};
|
};
|
||||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.condition.media.entry"),
|
PlaceWidgets(obs_module_text("AdvSceneSwitcher.condition.media.entry"),
|
||||||
layout, widgetPlaceholders);
|
entryLayout, widgetPlaceholders);
|
||||||
setLayout(layout);
|
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||||
|
mainLayout->addLayout(entryLayout);
|
||||||
|
mainLayout->addWidget(_onChange);
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
_entryData = entryData;
|
_entryData = entryData;
|
||||||
UpdateEntryData();
|
UpdateEntryData();
|
||||||
@@ -559,12 +572,28 @@ void MacroConditionMediaEdit::TimeChanged(const Duration &dur)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroConditionMediaEdit::OnChangeChanged(int value)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lock = LockContext();
|
||||||
|
_entryData->_onlyMatchOnChagne = value;
|
||||||
|
if (_entryData->_sourceType != MacroConditionMedia::Type::SOURCE) {
|
||||||
|
_entryData->UpdateMediaSourcesOfSceneList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MacroConditionMediaEdit::SetWidgetVisibility()
|
void MacroConditionMediaEdit::SetWidgetVisibility()
|
||||||
{
|
{
|
||||||
_sources->setVisible(_entryData->_sourceType ==
|
_sources->setVisible(_entryData->_sourceType ==
|
||||||
MacroConditionMedia::Type::SOURCE);
|
MacroConditionMedia::Type::SOURCE);
|
||||||
_scenes->setVisible(_entryData->_sourceType !=
|
_scenes->setVisible(_entryData->_sourceType !=
|
||||||
MacroConditionMedia::Type::SOURCE);
|
MacroConditionMedia::Type::SOURCE);
|
||||||
|
if (!_onChange->isChecked()) {
|
||||||
|
_onChange->hide();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getIdxFromMediaState(MacroConditionMedia::State state)
|
static int getIdxFromMediaState(MacroConditionMedia::State state)
|
||||||
@@ -596,6 +625,7 @@ void MacroConditionMediaEdit::UpdateEntryData()
|
|||||||
MacroConditionMedia::Time::TIME_RESTRICTION_NONE) {
|
MacroConditionMedia::Time::TIME_RESTRICTION_NONE) {
|
||||||
_time->setDisabled(true);
|
_time->setDisabled(true);
|
||||||
}
|
}
|
||||||
|
_onChange->setChecked(_entryData->_onlyMatchOnChagne);
|
||||||
SetWidgetVisibility();
|
SetWidgetVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ public:
|
|||||||
OBSWeakSource _rawSource = nullptr;
|
OBSWeakSource _rawSource = nullptr;
|
||||||
std::vector<MacroConditionMedia> _sourceGroup;
|
std::vector<MacroConditionMedia> _sourceGroup;
|
||||||
Duration _time;
|
Duration _time;
|
||||||
|
bool _onlyMatchOnChagne = false;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool CheckTime();
|
bool CheckTime();
|
||||||
@@ -83,7 +84,9 @@ private:
|
|||||||
bool _stopped = false;
|
bool _stopped = false;
|
||||||
bool _ended = false;
|
bool _ended = false;
|
||||||
bool _next = false;
|
bool _next = false;
|
||||||
|
// TODO: Remove _alreadyMatched as it does not make much sense when
|
||||||
|
// time restrictions for macro conditions are available.
|
||||||
|
bool _alreadyMatched = false;
|
||||||
// Workaround to enable use of "ended" to specify end of VLC playlist
|
// Workaround to enable use of "ended" to specify end of VLC playlist
|
||||||
bool _previousStateEnded = false;
|
bool _previousStateEnded = false;
|
||||||
// Used to keep track of scene changes
|
// Used to keep track of scene changes
|
||||||
@@ -116,6 +119,7 @@ private slots:
|
|||||||
void StateChanged(int index);
|
void StateChanged(int index);
|
||||||
void TimeRestrictionChanged(int index);
|
void TimeRestrictionChanged(int index);
|
||||||
void TimeChanged(const Duration &seconds);
|
void TimeChanged(const Duration &seconds);
|
||||||
|
void OnChangeChanged(int);
|
||||||
signals:
|
signals:
|
||||||
void HeaderInfoChanged(const QString &);
|
void HeaderInfoChanged(const QString &);
|
||||||
|
|
||||||
@@ -126,6 +130,7 @@ protected:
|
|||||||
QComboBox *_states;
|
QComboBox *_states;
|
||||||
QComboBox *_timeRestrictions;
|
QComboBox *_timeRestrictions;
|
||||||
DurationSelection *_time;
|
DurationSelection *_time;
|
||||||
|
QCheckBox *_onChange;
|
||||||
std::shared_ptr<MacroConditionMedia> _entryData;
|
std::shared_ptr<MacroConditionMedia> _entryData;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#include "macro-condition-plugin-state.hpp"
|
#include "macro-condition-plugin-state.hpp"
|
||||||
#include "macro-helpers.hpp"
|
#include "switcher-data.hpp"
|
||||||
#include "plugin-state-helpers.hpp"
|
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
@@ -34,7 +33,7 @@ const static std::map<MacroConditionPluginState::Condition, std::string>
|
|||||||
MacroConditionPluginState::~MacroConditionPluginState()
|
MacroConditionPluginState::~MacroConditionPluginState()
|
||||||
{
|
{
|
||||||
if (_condition == Condition::OBS_SHUTDOWN) {
|
if (_condition == Condition::OBS_SHUTDOWN) {
|
||||||
GetShutdownConditionCount()--;
|
switcher->shutdownConditionCount--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,15 +41,15 @@ bool MacroConditionPluginState::CheckCondition()
|
|||||||
{
|
{
|
||||||
switch (_condition) {
|
switch (_condition) {
|
||||||
case Condition::PLUGIN_SCENE_CHANGE:
|
case Condition::PLUGIN_SCENE_CHANGE:
|
||||||
return MacroSwitchedScene();
|
return switcher->macroSceneSwitched;
|
||||||
case Condition::PLUGIN_RUNNING:
|
case Condition::PLUGIN_RUNNING:
|
||||||
return true;
|
return true;
|
||||||
case Condition::OBS_SHUTDOWN:
|
case Condition::OBS_SHUTDOWN:
|
||||||
return OBSIsShuttingDown();
|
return switcher->obsIsShuttingDown;
|
||||||
case Condition::PLUGIN_START:
|
case Condition::PLUGIN_START:
|
||||||
return IsFirstInterval();
|
return switcher->firstInterval;
|
||||||
case Condition::PLUGIN_RESTART:
|
case Condition::PLUGIN_RESTART:
|
||||||
return IsFirstIntervalAfterStop();
|
return switcher->firstIntervalAfterStop;
|
||||||
case Condition::SCENE_COLLECTION_CHANGE:
|
case Condition::SCENE_COLLECTION_CHANGE:
|
||||||
if (_firstCheckAfterSceneCollectionChange) {
|
if (_firstCheckAfterSceneCollectionChange) {
|
||||||
_firstCheckAfterSceneCollectionChange = false;
|
_firstCheckAfterSceneCollectionChange = false;
|
||||||
@@ -84,33 +83,25 @@ bool MacroConditionPluginState::Load(obs_data_t *obj)
|
|||||||
obs_data_get_int(obj, "condition"));
|
obs_data_get_int(obj, "condition"));
|
||||||
switch (oldValue) {
|
switch (oldValue) {
|
||||||
case PluginStateCondition::SCENE_SWITCHED:
|
case PluginStateCondition::SCENE_SWITCHED:
|
||||||
SetCondition(Condition::PLUGIN_SCENE_CHANGE);
|
_condition = Condition::PLUGIN_SCENE_CHANGE;
|
||||||
break;
|
break;
|
||||||
case PluginStateCondition::RUNNING:
|
case PluginStateCondition::RUNNING:
|
||||||
SetCondition(Condition::PLUGIN_RUNNING);
|
_condition = Condition::PLUGIN_RUNNING;
|
||||||
break;
|
break;
|
||||||
case PluginStateCondition::SHUTDOWN:
|
case PluginStateCondition::SHUTDOWN:
|
||||||
SetCondition(Condition::OBS_SHUTDOWN);
|
_condition = Condition::OBS_SHUTDOWN;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
SetCondition(static_cast<Condition>(
|
_condition = static_cast<Condition>(
|
||||||
obs_data_get_int(obj, "condition")));
|
obs_data_get_int(obj, "condition"));
|
||||||
|
}
|
||||||
|
if (_condition == Condition::OBS_SHUTDOWN) {
|
||||||
|
switcher->shutdownConditionCount++;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionPluginState::SetCondition(Condition newValue)
|
|
||||||
{
|
|
||||||
if (_condition == Condition::OBS_SHUTDOWN) {
|
|
||||||
GetShutdownConditionCount()--;
|
|
||||||
}
|
|
||||||
if (newValue == Condition::OBS_SHUTDOWN) {
|
|
||||||
GetShutdownConditionCount()++;
|
|
||||||
}
|
|
||||||
_condition = newValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void populateConditionSelection(QComboBox *list)
|
static inline void populateConditionSelection(QComboBox *list)
|
||||||
{
|
{
|
||||||
for (const auto &[action, name] : pluginStateConditionTypes) {
|
for (const auto &[action, name] : pluginStateConditionTypes) {
|
||||||
@@ -157,9 +148,17 @@ void MacroConditionPluginStateEdit::ConditionChanged(int idx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto lock = LockContext();
|
auto lock = LockContext();
|
||||||
_entryData->SetCondition(
|
if (_entryData->_condition ==
|
||||||
|
MacroConditionPluginState::Condition::OBS_SHUTDOWN) {
|
||||||
|
switcher->shutdownConditionCount--;
|
||||||
|
}
|
||||||
|
_entryData->_condition =
|
||||||
static_cast<MacroConditionPluginState::Condition>(
|
static_cast<MacroConditionPluginState::Condition>(
|
||||||
_condition->itemData(idx).toInt()));
|
_condition->itemData(idx).toInt());
|
||||||
|
if (_entryData->_condition ==
|
||||||
|
MacroConditionPluginState::Condition::OBS_SHUTDOWN) {
|
||||||
|
switcher->shutdownConditionCount++;
|
||||||
|
}
|
||||||
SetWidgetVisibility();
|
SetWidgetVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,15 +168,15 @@ void MacroConditionPluginStateEdit::UpdateEntryData()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_condition->setCurrentIndex(_condition->findData(
|
_condition->setCurrentIndex(
|
||||||
static_cast<int>(_entryData->GetCondition())));
|
_condition->findData(static_cast<int>(_entryData->_condition)));
|
||||||
SetWidgetVisibility();
|
SetWidgetVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionPluginStateEdit::SetWidgetVisibility()
|
void MacroConditionPluginStateEdit::SetWidgetVisibility()
|
||||||
{
|
{
|
||||||
_shutdownLimitation->setVisible(
|
_shutdownLimitation->setVisible(
|
||||||
_entryData->GetCondition() ==
|
_entryData->_condition ==
|
||||||
MacroConditionPluginState::Condition::OBS_SHUTDOWN);
|
MacroConditionPluginState::Condition::OBS_SHUTDOWN);
|
||||||
adjustSize();
|
adjustSize();
|
||||||
updateGeometry();
|
updateGeometry();
|
||||||
|
|||||||
@@ -26,11 +26,10 @@ public:
|
|||||||
SCENE_COLLECTION_CHANGE,
|
SCENE_COLLECTION_CHANGE,
|
||||||
PLUGIN_SCENE_CHANGE,
|
PLUGIN_SCENE_CHANGE,
|
||||||
};
|
};
|
||||||
void SetCondition(Condition);
|
|
||||||
Condition GetCondition() const { return _condition; }
|
Condition _condition = Condition::PLUGIN_SCENE_CHANGE;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Condition _condition = Condition::PLUGIN_SCENE_CHANGE;
|
|
||||||
bool _firstCheckAfterSceneCollectionChange = true;
|
bool _firstCheckAfterSceneCollectionChange = true;
|
||||||
|
|
||||||
const static uint32_t _version;
|
const static uint32_t _version;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "macro-condition-process.hpp"
|
#include "macro-condition-process.hpp"
|
||||||
|
#include "switcher-data.hpp"
|
||||||
#include "platform-funcs.hpp"
|
#include "platform-funcs.hpp"
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
|
|
||||||
@@ -18,43 +19,25 @@ bool MacroConditionProcess::CheckCondition()
|
|||||||
QStringList runningProcesses;
|
QStringList runningProcesses;
|
||||||
QString proc = QString::fromStdString(_process);
|
QString proc = QString::fromStdString(_process);
|
||||||
GetProcessList(runningProcesses);
|
GetProcessList(runningProcesses);
|
||||||
std::string foregroundProcessName;
|
|
||||||
GetForegroundProcessName(foregroundProcessName);
|
|
||||||
|
|
||||||
SetVariableValue(foregroundProcessName);
|
bool equals = runningProcesses.contains(proc);
|
||||||
|
bool matches = runningProcesses.indexOf(QRegularExpression(proc)) != -1;
|
||||||
|
bool focus = !_focus || IsInFocus(proc);
|
||||||
|
|
||||||
if (!_regex.Enabled()) {
|
if (IsReferencedInVars()) {
|
||||||
if (runningProcesses.contains(proc) &&
|
std::string name;
|
||||||
(!_checkFocus || IsInFocus(proc))) {
|
GetForegroundProcessName(name);
|
||||||
SetTempVarValue("name", proc.toStdString());
|
SetVariableValue(name);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto matchIndex = runningProcesses.indexOf(QRegularExpression(proc));
|
return (equals || matches) && focus;
|
||||||
if (matchIndex == -1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!_checkFocus) {
|
|
||||||
SetTempVarValue("name",
|
|
||||||
runningProcesses.at(matchIndex).toStdString());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!IsInFocus(proc)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
SetTempVarValue("name", foregroundProcessName);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroConditionProcess::Save(obs_data_t *obj) const
|
bool MacroConditionProcess::Save(obs_data_t *obj) const
|
||||||
{
|
{
|
||||||
MacroCondition::Save(obj);
|
MacroCondition::Save(obj);
|
||||||
obs_data_set_string(obj, "process", _process.c_str());
|
obs_data_set_string(obj, "process", _process.c_str());
|
||||||
obs_data_set_bool(obj, "focus", _checkFocus);
|
obs_data_set_bool(obj, "focus", _focus);
|
||||||
_regex.Save(obj);
|
|
||||||
obs_data_set_int(obj, "version", 1);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,13 +45,7 @@ bool MacroConditionProcess::Load(obs_data_t *obj)
|
|||||||
{
|
{
|
||||||
MacroCondition::Load(obj);
|
MacroCondition::Load(obj);
|
||||||
_process = obs_data_get_string(obj, "process");
|
_process = obs_data_get_string(obj, "process");
|
||||||
_checkFocus = obs_data_get_bool(obj, "focus");
|
_focus = obs_data_get_bool(obj, "focus");
|
||||||
// Fall back to partial match regex as default for old version
|
|
||||||
if (!obs_data_has_user_value(obj, "version")) {
|
|
||||||
_regex.SetEnabled(true);
|
|
||||||
} else {
|
|
||||||
_regex.Load(obj);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,18 +54,10 @@ std::string MacroConditionProcess::GetShortDesc() const
|
|||||||
return _process;
|
return _process;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionProcess::SetupTempVars()
|
|
||||||
{
|
|
||||||
MacroCondition::SetupTempVars();
|
|
||||||
AddTempvar("name",
|
|
||||||
obs_module_text("AdvSceneSwitcher.tempVar.process.name"));
|
|
||||||
}
|
|
||||||
|
|
||||||
MacroConditionProcessEdit::MacroConditionProcessEdit(
|
MacroConditionProcessEdit::MacroConditionProcessEdit(
|
||||||
QWidget *parent, std::shared_ptr<MacroConditionProcess> entryData)
|
QWidget *parent, std::shared_ptr<MacroConditionProcess> entryData)
|
||||||
: QWidget(parent),
|
: QWidget(parent),
|
||||||
_processSelection(new QComboBox()),
|
_processSelection(new QComboBox()),
|
||||||
_regex(new RegexConfigWidget(this)),
|
|
||||||
_focused(new QCheckBox()),
|
_focused(new QCheckBox()),
|
||||||
_focusProcess(new QLabel()),
|
_focusProcess(new QLabel()),
|
||||||
_focusLayout(new QHBoxLayout())
|
_focusLayout(new QHBoxLayout())
|
||||||
@@ -99,8 +68,6 @@ MacroConditionProcessEdit::MacroConditionProcessEdit(
|
|||||||
QWidget::connect(_processSelection,
|
QWidget::connect(_processSelection,
|
||||||
SIGNAL(currentTextChanged(const QString &)), this,
|
SIGNAL(currentTextChanged(const QString &)), this,
|
||||||
SLOT(ProcessChanged(const QString &)));
|
SLOT(ProcessChanged(const QString &)));
|
||||||
QWidget::connect(_regex, SIGNAL(RegexConfigChanged(RegexConfig)), this,
|
|
||||||
SLOT(RegexChanged(RegexConfig)));
|
|
||||||
QWidget::connect(_focused, SIGNAL(stateChanged(int)), this,
|
QWidget::connect(_focused, SIGNAL(stateChanged(int)), this,
|
||||||
SLOT(FocusChanged(int)));
|
SLOT(FocusChanged(int)));
|
||||||
QWidget::connect(&_timer, SIGNAL(timeout()), this,
|
QWidget::connect(&_timer, SIGNAL(timeout()), this,
|
||||||
@@ -110,7 +77,6 @@ MacroConditionProcessEdit::MacroConditionProcessEdit(
|
|||||||
|
|
||||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
{"{{processes}}", _processSelection},
|
{"{{processes}}", _processSelection},
|
||||||
{"{{regex}}", _regex},
|
|
||||||
{"{{focused}}", _focused},
|
{"{{focused}}", _focused},
|
||||||
{"{{focusProcess}}", _focusProcess},
|
{"{{focusProcess}}", _focusProcess},
|
||||||
};
|
};
|
||||||
@@ -146,18 +112,6 @@ void MacroConditionProcessEdit::ProcessChanged(const QString &text)
|
|||||||
QString::fromStdString(_entryData->GetShortDesc()));
|
QString::fromStdString(_entryData->GetShortDesc()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionProcessEdit::RegexChanged(RegexConfig conf)
|
|
||||||
{
|
|
||||||
if (_loading || !_entryData) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto lock = LockContext();
|
|
||||||
_entryData->_regex = conf;
|
|
||||||
adjustSize();
|
|
||||||
updateGeometry();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroConditionProcessEdit::FocusChanged(int state)
|
void MacroConditionProcessEdit::FocusChanged(int state)
|
||||||
{
|
{
|
||||||
if (_loading || !_entryData) {
|
if (_loading || !_entryData) {
|
||||||
@@ -165,15 +119,14 @@ void MacroConditionProcessEdit::FocusChanged(int state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto lock = LockContext();
|
auto lock = LockContext();
|
||||||
_entryData->_checkFocus = state;
|
_entryData->_focus = state;
|
||||||
SetWidgetVisibility();
|
SetWidgetVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionProcessEdit::UpdateFocusProcess()
|
void MacroConditionProcessEdit::UpdateFocusProcess()
|
||||||
{
|
{
|
||||||
std::string name;
|
_focusProcess->setText(
|
||||||
GetForegroundProcessName(name);
|
QString::fromStdString(switcher->currentForegroundProcess));
|
||||||
_focusProcess->setText(QString::fromStdString(name));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionProcessEdit::SetWidgetVisibility()
|
void MacroConditionProcessEdit::SetWidgetVisibility()
|
||||||
@@ -181,7 +134,7 @@ void MacroConditionProcessEdit::SetWidgetVisibility()
|
|||||||
if (!_entryData) {
|
if (!_entryData) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SetLayoutVisible(_focusLayout, _entryData->_checkFocus);
|
SetLayoutVisible(_focusLayout, _entryData->_focus);
|
||||||
adjustSize();
|
adjustSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,8 +145,7 @@ void MacroConditionProcessEdit::UpdateEntryData()
|
|||||||
}
|
}
|
||||||
|
|
||||||
_processSelection->setCurrentText(_entryData->_process.c_str());
|
_processSelection->setCurrentText(_entryData->_process.c_str());
|
||||||
_regex->SetRegexConfig(_entryData->_regex);
|
_focused->setChecked(_entryData->_focus);
|
||||||
_focused->setChecked(_entryData->_checkFocus);
|
|
||||||
SetWidgetVisibility();
|
SetWidgetVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "macro-condition-edit.hpp"
|
#include "macro-condition-edit.hpp"
|
||||||
#include "regex-config.hpp"
|
|
||||||
|
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
@@ -21,12 +20,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string _process;
|
std::string _process;
|
||||||
bool _checkFocus = true;
|
bool _focus = true;
|
||||||
RegexConfig _regex = RegexConfig::PartialMatchRegexConfig();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SetupTempVars();
|
|
||||||
|
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
static const std::string id;
|
static const std::string id;
|
||||||
};
|
};
|
||||||
@@ -49,22 +45,22 @@ public:
|
|||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void ProcessChanged(const QString &text);
|
void ProcessChanged(const QString &text);
|
||||||
void RegexChanged(RegexConfig);
|
|
||||||
void FocusChanged(int state);
|
void FocusChanged(int state);
|
||||||
void UpdateFocusProcess();
|
void UpdateFocusProcess();
|
||||||
signals:
|
signals:
|
||||||
void HeaderInfoChanged(const QString &);
|
void HeaderInfoChanged(const QString &);
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
void SetWidgetVisibility();
|
|
||||||
|
|
||||||
QComboBox *_processSelection;
|
QComboBox *_processSelection;
|
||||||
RegexConfigWidget *_regex;
|
|
||||||
QCheckBox *_focused;
|
QCheckBox *_focused;
|
||||||
QLabel *_focusProcess;
|
QLabel *_focusProcess;
|
||||||
QHBoxLayout *_focusLayout;
|
QHBoxLayout *_focusLayout;
|
||||||
QTimer _timer;
|
QTimer _timer;
|
||||||
std::shared_ptr<MacroConditionProcess> _entryData;
|
std::shared_ptr<MacroConditionProcess> _entryData;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void SetWidgetVisibility();
|
||||||
|
|
||||||
bool _loading = true;
|
bool _loading = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
#include "macro-condition-recording.hpp"
|
#include "macro-condition-recording.hpp"
|
||||||
|
#include "macro.hpp"
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
const std::string MacroConditionRecord::id = "recording";
|
const std::string MacroConditionRecord::id = "recording";
|
||||||
@@ -20,13 +19,29 @@ const static std::map<MacroConditionRecord::Condition, std::string>
|
|||||||
"AdvSceneSwitcher.condition.record.state.pause"},
|
"AdvSceneSwitcher.condition.record.state.pause"},
|
||||||
{MacroConditionRecord::Condition::START,
|
{MacroConditionRecord::Condition::START,
|
||||||
"AdvSceneSwitcher.condition.record.state.start"},
|
"AdvSceneSwitcher.condition.record.state.start"},
|
||||||
{MacroConditionRecord::Condition::DURATION,
|
{MacroConditionRecord::Condition::SAVE_DONE,
|
||||||
"AdvSceneSwitcher.condition.record.state.duration"},
|
"AdvSceneSwitcher.condition.record.state.saveDone"},
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool SetupRecordingTimer();
|
MacroConditionRecord::MacroConditionRecord(Macro *m) : MacroCondition(m)
|
||||||
static bool recordingTimerIsSetup = SetupRecordingTimer();
|
{
|
||||||
static int currentRecordingDurationInSeconds = 0;
|
OBSOutputAutoRelease output = obs_frontend_get_recording_output();
|
||||||
|
if (!output) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto sh = obs_output_get_signal_handler(output);
|
||||||
|
signal_handler_connect(sh, "stop", StopSignal, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
MacroConditionRecord::~MacroConditionRecord()
|
||||||
|
{
|
||||||
|
OBSOutputAutoRelease output = obs_frontend_get_recording_output();
|
||||||
|
if (!output) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto sh = obs_output_get_signal_handler(output);
|
||||||
|
signal_handler_disconnect(sh, "stop", StopSignal, this);
|
||||||
|
}
|
||||||
|
|
||||||
bool MacroConditionRecord::CheckCondition()
|
bool MacroConditionRecord::CheckCondition()
|
||||||
{
|
{
|
||||||
@@ -37,11 +52,12 @@ bool MacroConditionRecord::CheckCondition()
|
|||||||
return obs_frontend_recording_paused();
|
return obs_frontend_recording_paused();
|
||||||
case Condition::START:
|
case Condition::START:
|
||||||
return obs_frontend_recording_active();
|
return obs_frontend_recording_active();
|
||||||
case Condition::DURATION:
|
case Condition::SAVE_DONE:
|
||||||
SetTempVarValue(
|
if (_recordingSaveDone) {
|
||||||
"durationSeconds",
|
_recordingSaveDone = false;
|
||||||
std::to_string(currentRecordingDurationInSeconds));
|
return true;
|
||||||
return currentRecordingDurationInSeconds > _duration.Seconds();
|
}
|
||||||
|
return false;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -52,7 +68,6 @@ bool MacroConditionRecord::Save(obs_data_t *obj) const
|
|||||||
{
|
{
|
||||||
MacroCondition::Save(obj);
|
MacroCondition::Save(obj);
|
||||||
obs_data_set_int(obj, "state", static_cast<int>(_condition));
|
obs_data_set_int(obj, "state", static_cast<int>(_condition));
|
||||||
_duration.Save(obj);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,30 +75,24 @@ bool MacroConditionRecord::Load(obs_data_t *obj)
|
|||||||
{
|
{
|
||||||
MacroCondition::Load(obj);
|
MacroCondition::Load(obj);
|
||||||
_condition = static_cast<Condition>(obs_data_get_int(obj, "state"));
|
_condition = static_cast<Condition>(obs_data_get_int(obj, "state"));
|
||||||
_duration.Load(obj);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionRecord::SetCondition(Condition condition)
|
void MacroConditionRecord::StopSignal(void *c, calldata_t *data)
|
||||||
{
|
{
|
||||||
_condition = condition;
|
auto condition = static_cast<MacroConditionRecord *>(c);
|
||||||
SetupTempVars();
|
const auto macro = condition->GetMacro();
|
||||||
}
|
if (macro && macro->Paused()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void MacroConditionRecord::SetupTempVars()
|
long long code = 0;
|
||||||
{
|
if (!calldata_get_int(data, "code", &code)) {
|
||||||
MacroCondition::SetupTempVars();
|
condition->_recordingSaveDone = false;
|
||||||
switch (_condition) {
|
}
|
||||||
case Condition::DURATION:
|
|
||||||
AddTempvar(
|
if (code == OBS_OUTPUT_SUCCESS) {
|
||||||
"durationSeconds",
|
condition->_recordingSaveDone = true;
|
||||||
obs_module_text(
|
|
||||||
"AdvSceneSwitcher.tempVar.recording.durationSeconds"),
|
|
||||||
obs_module_text(
|
|
||||||
"AdvSceneSwitcher.tempVar.recording.durationSeconds.description"));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,39 +105,39 @@ static inline void populateStateSelection(QComboBox *list)
|
|||||||
|
|
||||||
MacroConditionRecordEdit::MacroConditionRecordEdit(
|
MacroConditionRecordEdit::MacroConditionRecordEdit(
|
||||||
QWidget *parent, std::shared_ptr<MacroConditionRecord> entryData)
|
QWidget *parent, std::shared_ptr<MacroConditionRecord> entryData)
|
||||||
: QWidget(parent),
|
: QWidget(parent)
|
||||||
_condition(new QComboBox(this)),
|
|
||||||
_duration(new DurationSelection(this))
|
|
||||||
{
|
{
|
||||||
populateStateSelection(_condition);
|
_recordState = new QComboBox();
|
||||||
|
|
||||||
QWidget::connect(_condition, SIGNAL(currentIndexChanged(int)), this,
|
QWidget::connect(_recordState, SIGNAL(currentIndexChanged(int)), this,
|
||||||
SLOT(ConditionChanged(int)));
|
SLOT(StateChanged(int)));
|
||||||
QWidget::connect(_duration, SIGNAL(DurationChanged(const Duration &)),
|
|
||||||
this, SLOT(DurationChanged(const Duration &)));
|
populateStateSelection(_recordState);
|
||||||
|
|
||||||
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
|
{"{{recordState}}", _recordState},
|
||||||
|
};
|
||||||
|
|
||||||
auto layout = new QHBoxLayout;
|
|
||||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.condition.record.entry"),
|
PlaceWidgets(obs_module_text("AdvSceneSwitcher.condition.record.entry"),
|
||||||
layout,
|
mainLayout, widgetPlaceholders);
|
||||||
{{"{{condition}}", _condition},
|
setLayout(mainLayout);
|
||||||
{"{{duration}}", _duration}});
|
|
||||||
setLayout(layout);
|
|
||||||
|
|
||||||
_entryData = entryData;
|
_entryData = entryData;
|
||||||
UpdateEntryData();
|
UpdateEntryData();
|
||||||
_loading = false;
|
_loading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionRecordEdit::ConditionChanged(int value)
|
void MacroConditionRecordEdit::StateChanged(int value)
|
||||||
{
|
{
|
||||||
if (_loading || !_entryData) {
|
if (_loading || !_entryData) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lock = LockContext();
|
auto lock = LockContext();
|
||||||
_entryData->SetCondition(
|
_entryData->_condition =
|
||||||
static_cast<MacroConditionRecord::Condition>(value));
|
static_cast<MacroConditionRecord::Condition>(value);
|
||||||
SetWidgetVisibility();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionRecordEdit::UpdateEntryData()
|
void MacroConditionRecordEdit::UpdateEntryData()
|
||||||
@@ -137,67 +146,7 @@ void MacroConditionRecordEdit::UpdateEntryData()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_condition->setCurrentIndex(
|
_recordState->setCurrentIndex(static_cast<int>(_entryData->_condition));
|
||||||
static_cast<int>(_entryData->GetCondition()));
|
|
||||||
_duration->SetDuration(_entryData->_duration);
|
|
||||||
SetWidgetVisibility();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroConditionRecordEdit::DurationChanged(const Duration &duration)
|
|
||||||
{
|
|
||||||
if (_loading || !_entryData) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto lock = LockContext();
|
|
||||||
_entryData->_duration = duration;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroConditionRecordEdit::SetWidgetVisibility()
|
|
||||||
{
|
|
||||||
_duration->setVisible(_entryData->GetCondition() ==
|
|
||||||
MacroConditionRecord::Condition::DURATION);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SetupRecordingTimer()
|
|
||||||
{
|
|
||||||
static std::atomic_bool recordingStopped = {true};
|
|
||||||
static std::atomic_bool recordingPaused = {false};
|
|
||||||
static auto handleRecordingEvents = [](enum obs_frontend_event event,
|
|
||||||
void *) {
|
|
||||||
switch (event) {
|
|
||||||
case OBS_FRONTEND_EVENT_RECORDING_STOPPED:
|
|
||||||
recordingStopped = true;
|
|
||||||
break;
|
|
||||||
case OBS_FRONTEND_EVENT_RECORDING_STARTED:
|
|
||||||
recordingStopped = false;
|
|
||||||
break;
|
|
||||||
case OBS_FRONTEND_EVENT_RECORDING_PAUSED:
|
|
||||||
recordingPaused = true;
|
|
||||||
break;
|
|
||||||
case OBS_FRONTEND_EVENT_RECORDING_UNPAUSED:
|
|
||||||
recordingPaused = false;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
obs_frontend_add_event_callback(handleRecordingEvents, nullptr);
|
|
||||||
std::thread thread([]() {
|
|
||||||
while (true) {
|
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
|
||||||
if (recordingStopped) {
|
|
||||||
currentRecordingDurationInSeconds = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (recordingPaused) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
++currentRecordingDurationInSeconds;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
thread.detach();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ namespace advss {
|
|||||||
|
|
||||||
class MacroConditionRecord : public MacroCondition {
|
class MacroConditionRecord : public MacroCondition {
|
||||||
public:
|
public:
|
||||||
MacroConditionRecord(Macro *m) : MacroCondition(m) {}
|
MacroConditionRecord(Macro *m);
|
||||||
|
~MacroConditionRecord();
|
||||||
bool CheckCondition();
|
bool CheckCondition();
|
||||||
bool Save(obs_data_t *obj) const;
|
bool Save(obs_data_t *obj) const;
|
||||||
bool Load(obs_data_t *obj);
|
bool Load(obs_data_t *obj);
|
||||||
@@ -22,17 +23,14 @@ public:
|
|||||||
STOP,
|
STOP,
|
||||||
PAUSE,
|
PAUSE,
|
||||||
START,
|
START,
|
||||||
DURATION,
|
SAVE_DONE,
|
||||||
};
|
};
|
||||||
|
Condition _condition = Condition::STOP;
|
||||||
void SetCondition(Condition);
|
|
||||||
Condition GetCondition() const { return _condition; }
|
|
||||||
Duration _duration;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SetupTempVars();
|
static void StopSignal(void *condition, calldata_t *);
|
||||||
|
bool _recordingSaveDone = false;
|
||||||
|
|
||||||
Condition _condition = Condition::STOP;
|
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
static const std::string id;
|
static const std::string id;
|
||||||
};
|
};
|
||||||
@@ -54,15 +52,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void ConditionChanged(int value);
|
void StateChanged(int value);
|
||||||
void DurationChanged(const Duration &);
|
|
||||||
|
protected:
|
||||||
|
QComboBox *_recordState;
|
||||||
|
std::shared_ptr<MacroConditionRecord> _entryData;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SetWidgetVisibility();
|
|
||||||
|
|
||||||
QComboBox *_condition;
|
|
||||||
DurationSelection *_duration;
|
|
||||||
std::shared_ptr<MacroConditionRecord> _entryData;
|
|
||||||
bool _loading = true;
|
bool _loading = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "macro-condition-replay-buffer.hpp"
|
#include "macro-condition-replay-buffer.hpp"
|
||||||
|
#include "switcher-data.hpp"
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
@@ -10,63 +11,35 @@ bool MacroConditionReplayBuffer::_registered = MacroConditionFactory::Register(
|
|||||||
MacroConditionReplayBufferEdit::Create,
|
MacroConditionReplayBufferEdit::Create,
|
||||||
"AdvSceneSwitcher.condition.replay"});
|
"AdvSceneSwitcher.condition.replay"});
|
||||||
|
|
||||||
const static std::map<MacroConditionReplayBuffer::Condition, std::string>
|
const static std::map<ReplayBufferState, std::string> ReplayBufferStates = {
|
||||||
conditions = {
|
{ReplayBufferState::STOP,
|
||||||
{MacroConditionReplayBuffer::Condition::STOP,
|
"AdvSceneSwitcher.condition.replay.state.stopped"},
|
||||||
"AdvSceneSwitcher.condition.replay.state.stopped"},
|
{ReplayBufferState::START,
|
||||||
{MacroConditionReplayBuffer::Condition::START,
|
"AdvSceneSwitcher.condition.replay.state.started"},
|
||||||
"AdvSceneSwitcher.condition.replay.state.started"},
|
{ReplayBufferState::SAVE,
|
||||||
{MacroConditionReplayBuffer::Condition::SAVE,
|
"AdvSceneSwitcher.condition.replay.state.saved"},
|
||||||
"AdvSceneSwitcher.condition.replay.state.saved"},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool replayBufferSaved = false;
|
|
||||||
|
|
||||||
static std::chrono::high_resolution_clock::time_point replayBufferSaveTime{};
|
|
||||||
static bool setupReplayBufferEventHandler();
|
|
||||||
static bool replayBufferEventHandlerIsSetup = setupReplayBufferEventHandler();
|
|
||||||
|
|
||||||
static bool setupReplayBufferEventHandler()
|
|
||||||
{
|
|
||||||
static auto handleReplayBufferEvent = [](enum obs_frontend_event event,
|
|
||||||
void *) {
|
|
||||||
switch (event) {
|
|
||||||
case OBS_FRONTEND_EVENT_REPLAY_BUFFER_SAVED:
|
|
||||||
replayBufferSaveTime =
|
|
||||||
std::chrono::high_resolution_clock::now();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
obs_frontend_add_event_callback(handleReplayBufferEvent, nullptr);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MacroConditionReplayBuffer::ReplayBufferWasSaved()
|
|
||||||
{
|
|
||||||
bool timersAreInitialized =
|
|
||||||
_saveTime.time_since_epoch().count() != 0 &&
|
|
||||||
replayBufferSaveTime.time_since_epoch().count() != 0;
|
|
||||||
bool newSaveOccurred = timersAreInitialized &&
|
|
||||||
_saveTime != replayBufferSaveTime;
|
|
||||||
_saveTime = replayBufferSaveTime;
|
|
||||||
return newSaveOccurred;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MacroConditionReplayBuffer::CheckCondition()
|
bool MacroConditionReplayBuffer::CheckCondition()
|
||||||
{
|
{
|
||||||
|
bool stateMatch = false;
|
||||||
switch (_state) {
|
switch (_state) {
|
||||||
case Condition::STOP:
|
case ReplayBufferState::STOP:
|
||||||
return !obs_frontend_replay_buffer_active();
|
stateMatch = !obs_frontend_replay_buffer_active();
|
||||||
case Condition::START:
|
break;
|
||||||
return obs_frontend_replay_buffer_active();
|
case ReplayBufferState::START:
|
||||||
case Condition::SAVE:
|
stateMatch = obs_frontend_replay_buffer_active();
|
||||||
return ReplayBufferWasSaved();
|
break;
|
||||||
|
case ReplayBufferState::SAVE:
|
||||||
|
if (switcher->replayBufferSaved) {
|
||||||
|
stateMatch = true;
|
||||||
|
switcher->replayBufferSaved = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return false;
|
return stateMatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroConditionReplayBuffer::Save(obs_data_t *obj) const
|
bool MacroConditionReplayBuffer::Save(obs_data_t *obj) const
|
||||||
@@ -79,30 +52,37 @@ bool MacroConditionReplayBuffer::Save(obs_data_t *obj) const
|
|||||||
bool MacroConditionReplayBuffer::Load(obs_data_t *obj)
|
bool MacroConditionReplayBuffer::Load(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
MacroCondition::Load(obj);
|
MacroCondition::Load(obj);
|
||||||
_state = static_cast<Condition>(obs_data_get_int(obj, "state"));
|
_state = static_cast<ReplayBufferState>(obs_data_get_int(obj, "state"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void populateStateSelection(QComboBox *list)
|
static inline void populateStateSelection(QComboBox *list)
|
||||||
{
|
{
|
||||||
for (const auto &entry : conditions) {
|
for (auto entry : ReplayBufferStates) {
|
||||||
list->addItem(obs_module_text(entry.second.c_str()));
|
list->addItem(obs_module_text(entry.second.c_str()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MacroConditionReplayBufferEdit::MacroConditionReplayBufferEdit(
|
MacroConditionReplayBufferEdit::MacroConditionReplayBufferEdit(
|
||||||
QWidget *parent, std::shared_ptr<MacroConditionReplayBuffer> entryData)
|
QWidget *parent, std::shared_ptr<MacroConditionReplayBuffer> entryData)
|
||||||
: QWidget(parent), _state(new QComboBox())
|
: QWidget(parent)
|
||||||
{
|
{
|
||||||
|
_state = new QComboBox();
|
||||||
|
|
||||||
QWidget::connect(_state, SIGNAL(currentIndexChanged(int)), this,
|
QWidget::connect(_state, SIGNAL(currentIndexChanged(int)), this,
|
||||||
SLOT(StateChanged(int)));
|
SLOT(StateChanged(int)));
|
||||||
|
|
||||||
populateStateSelection(_state);
|
populateStateSelection(_state);
|
||||||
|
|
||||||
auto layout = new QHBoxLayout;
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
|
{"{{state}}", _state},
|
||||||
|
};
|
||||||
|
|
||||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.condition.replay.entry"),
|
PlaceWidgets(obs_module_text("AdvSceneSwitcher.condition.replay.entry"),
|
||||||
layout, {{"{{state}}", _state}});
|
mainLayout, widgetPlaceholders);
|
||||||
setLayout(layout);
|
setLayout(mainLayout);
|
||||||
|
|
||||||
_entryData = entryData;
|
_entryData = entryData;
|
||||||
UpdateEntryData();
|
UpdateEntryData();
|
||||||
@@ -116,8 +96,7 @@ void MacroConditionReplayBufferEdit::StateChanged(int value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto lock = LockContext();
|
auto lock = LockContext();
|
||||||
_entryData->_state =
|
_entryData->_state = static_cast<ReplayBufferState>(value);
|
||||||
static_cast<MacroConditionReplayBuffer::Condition>(value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionReplayBufferEdit::UpdateEntryData()
|
void MacroConditionReplayBufferEdit::UpdateEntryData()
|
||||||
|
|||||||
@@ -6,6 +6,12 @@
|
|||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
|
enum class ReplayBufferState {
|
||||||
|
STOP,
|
||||||
|
START,
|
||||||
|
SAVE,
|
||||||
|
};
|
||||||
|
|
||||||
class MacroConditionReplayBuffer : public MacroCondition {
|
class MacroConditionReplayBuffer : public MacroCondition {
|
||||||
public:
|
public:
|
||||||
MacroConditionReplayBuffer(Macro *m) : MacroCondition(m) {}
|
MacroConditionReplayBuffer(Macro *m) : MacroCondition(m) {}
|
||||||
@@ -18,18 +24,9 @@ public:
|
|||||||
return std::make_shared<MacroConditionReplayBuffer>(m);
|
return std::make_shared<MacroConditionReplayBuffer>(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Condition {
|
ReplayBufferState _state = ReplayBufferState::STOP;
|
||||||
STOP,
|
|
||||||
START,
|
|
||||||
SAVE,
|
|
||||||
};
|
|
||||||
|
|
||||||
Condition _state = Condition::STOP;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool ReplayBufferWasSaved();
|
|
||||||
|
|
||||||
std::chrono::high_resolution_clock::time_point _saveTime = {};
|
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
static const std::string id;
|
static const std::string id;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
|
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
|
#include <QDesktopServices>
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
@@ -27,18 +28,17 @@ bool MacroConditionRun::CheckCondition()
|
|||||||
|
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
switch (_error) {
|
switch (_procStatus) {
|
||||||
case ProcessConfig::ProcStartError::FAILED_TO_START:
|
case MacroConditionRun::Status::FAILED_TO_START:
|
||||||
SetVariableValue("Failed to start process");
|
SetVariableValue("Failed to start process");
|
||||||
|
ret = false;
|
||||||
break;
|
break;
|
||||||
case ProcessConfig::ProcStartError::TIMEOUT:
|
case MacroConditionRun::Status::TIMEOUT:
|
||||||
SetVariableValue("Timeout while running process");
|
SetVariableValue("Timeout while running process");
|
||||||
|
ret = false;
|
||||||
break;
|
break;
|
||||||
case ProcessConfig::ProcStartError::CRASH:
|
case MacroConditionRun::Status::OK:
|
||||||
SetVariableValue("Timeout while running process");
|
ret = _checkExitCode ? _exitCode == _procExitCode : true;
|
||||||
break;
|
|
||||||
case ProcessConfig::ProcStartError::NONE:
|
|
||||||
ret = _checkExitCode ? _exitCodeToCheck == _procExitCode : true;
|
|
||||||
SetVariableValue(std::to_string(_procExitCode));
|
SetVariableValue(std::to_string(_procExitCode));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -56,14 +56,42 @@ bool MacroConditionRun::CheckCondition()
|
|||||||
|
|
||||||
void MacroConditionRun::RunProcess()
|
void MacroConditionRun::RunProcess()
|
||||||
{
|
{
|
||||||
auto result = _procConfig.StartProcessAndWait(_timeout.Milliseconds());
|
QProcess process;
|
||||||
|
process.setWorkingDirectory(
|
||||||
|
QString::fromStdString(_procConfig.WorkingDir()));
|
||||||
|
process.start(QString::fromStdString(_procConfig.Path()),
|
||||||
|
_procConfig.Args());
|
||||||
|
int timeout = _timeout.Milliseconds();
|
||||||
|
|
||||||
if (std::holds_alternative<ProcessConfig::ProcStartError>(result)) {
|
vblog(LOG_INFO, "run \"%s\" with a timeout of %d ms",
|
||||||
_error = std::get<ProcessConfig::ProcStartError>(result);
|
_procConfig.Path().c_str(), timeout);
|
||||||
} else {
|
|
||||||
_error = ProcessConfig::ProcStartError::NONE;
|
bool procFinishedInTime = process.waitForFinished(timeout);
|
||||||
_procExitCode = std::get<int>(result);
|
|
||||||
|
if (!procFinishedInTime) {
|
||||||
|
if (process.error() == QProcess::FailedToStart) {
|
||||||
|
vblog(LOG_INFO, "failed to start \"%s\"!",
|
||||||
|
_procConfig.Path().c_str());
|
||||||
|
_procStatus = Status::FAILED_TO_START;
|
||||||
|
} else {
|
||||||
|
vblog(LOG_INFO,
|
||||||
|
"timeout while running \"%s\"\nAttempting to kill process!",
|
||||||
|
_procConfig.Path().c_str());
|
||||||
|
process.kill();
|
||||||
|
process.waitForFinished();
|
||||||
|
_procStatus = Status::TIMEOUT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool validExitCode = process.exitStatus() == QProcess::NormalExit;
|
||||||
|
|
||||||
|
if ((_checkExitCode && !validExitCode) || !procFinishedInTime) {
|
||||||
|
_threadDone = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_procExitCode = process.exitCode();
|
||||||
|
_procStatus = Status::OK;
|
||||||
_threadDone = true;
|
_threadDone = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,7 +100,7 @@ bool MacroConditionRun::Save(obs_data_t *obj) const
|
|||||||
MacroCondition::Save(obj);
|
MacroCondition::Save(obj);
|
||||||
_procConfig.Save(obj);
|
_procConfig.Save(obj);
|
||||||
obs_data_set_bool(obj, "checkExitCode", _checkExitCode);
|
obs_data_set_bool(obj, "checkExitCode", _checkExitCode);
|
||||||
obs_data_set_int(obj, "exitCode", _exitCodeToCheck);
|
obs_data_set_int(obj, "exitCode", _exitCode);
|
||||||
_timeout.Save(obj, "timeout");
|
_timeout.Save(obj, "timeout");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -82,7 +110,7 @@ bool MacroConditionRun::Load(obs_data_t *obj)
|
|||||||
MacroCondition::Load(obj);
|
MacroCondition::Load(obj);
|
||||||
_procConfig.Load(obj);
|
_procConfig.Load(obj);
|
||||||
_checkExitCode = obs_data_get_bool(obj, "checkExitCode");
|
_checkExitCode = obs_data_get_bool(obj, "checkExitCode");
|
||||||
_exitCodeToCheck = obs_data_get_int(obj, "exitCode");
|
_exitCode = obs_data_get_int(obj, "exitCode");
|
||||||
_timeout.Load(obj, "timeout");
|
_timeout.Load(obj, "timeout");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -146,7 +174,7 @@ void MacroConditionRunEdit::UpdateEntryData()
|
|||||||
_procConfig->SetProcessConfig(_entryData->_procConfig);
|
_procConfig->SetProcessConfig(_entryData->_procConfig);
|
||||||
_timeout->SetDuration(_entryData->_timeout);
|
_timeout->SetDuration(_entryData->_timeout);
|
||||||
_checkExitCode->setChecked(_entryData->_checkExitCode);
|
_checkExitCode->setChecked(_entryData->_checkExitCode);
|
||||||
_exitCode->setValue(_entryData->_exitCodeToCheck);
|
_exitCode->setValue(_entryData->_exitCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionRunEdit::TimeoutChanged(const Duration &dur)
|
void MacroConditionRunEdit::TimeoutChanged(const Duration &dur)
|
||||||
@@ -176,7 +204,7 @@ void MacroConditionRunEdit::ExitCodeChanged(int exitCode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto lock = LockContext();
|
auto lock = LockContext();
|
||||||
_entryData->_exitCodeToCheck = exitCode;
|
_entryData->_exitCode = exitCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionRunEdit::ProcessConfigChanged(const ProcessConfig &conf)
|
void MacroConditionRunEdit::ProcessConfigChanged(const ProcessConfig &conf)
|
||||||
|
|||||||
@@ -25,15 +25,22 @@ public:
|
|||||||
|
|
||||||
ProcessConfig _procConfig;
|
ProcessConfig _procConfig;
|
||||||
bool _checkExitCode = true;
|
bool _checkExitCode = true;
|
||||||
int _exitCodeToCheck = 0;
|
int _exitCode = 0;
|
||||||
Duration _timeout = Duration(0.1);
|
Duration _timeout = Duration(0.1);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
enum class Status {
|
||||||
|
NONE,
|
||||||
|
FAILED_TO_START,
|
||||||
|
TIMEOUT,
|
||||||
|
OK,
|
||||||
|
};
|
||||||
|
|
||||||
void RunProcess();
|
void RunProcess();
|
||||||
|
|
||||||
std::thread _thread;
|
std::thread _thread;
|
||||||
std::atomic_bool _threadDone{true};
|
std::atomic_bool _threadDone{true};
|
||||||
ProcessConfig::ProcStartError _error =
|
Status _procStatus = Status::NONE;
|
||||||
ProcessConfig::ProcStartError::NONE;
|
|
||||||
int _procExitCode = 0;
|
int _procExitCode = 0;
|
||||||
|
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "macro-condition-scene.hpp"
|
#include "macro-condition-scene.hpp"
|
||||||
#include "scene-switch-helpers.hpp"
|
#include "switcher-data.hpp"
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
@@ -53,22 +53,23 @@ static OBSWeakSource getCurrentSceneHelper(bool useTransitionTargetScene)
|
|||||||
obs_source_release(current);
|
obs_source_release(current);
|
||||||
return weak;
|
return weak;
|
||||||
}
|
}
|
||||||
return GetCurrentScene();
|
return switcher->currentScene;
|
||||||
}
|
}
|
||||||
|
|
||||||
static OBSWeakSource getPreviousSceneHelper(bool useTransitionTargetScene)
|
static OBSWeakSource getPreviousSceneHelper(bool useTransitionTargetScene)
|
||||||
{
|
{
|
||||||
if (AnySceneTransitionStarted() && useTransitionTargetScene) {
|
if (switcher->AnySceneTransitionStarted() && useTransitionTargetScene) {
|
||||||
return GetCurrentScene();
|
return switcher->currentScene;
|
||||||
}
|
}
|
||||||
return GetPreviousScene();
|
return switcher->previousScene;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroConditionScene::CheckCondition()
|
bool MacroConditionScene::CheckCondition()
|
||||||
{
|
{
|
||||||
bool sceneChanged = _lastSceneChangeTime != GetLastSceneChangeTime();
|
bool sceneChanged = _lastSceneChangeTime !=
|
||||||
|
switcher->lastSceneChangeTime;
|
||||||
if (sceneChanged) {
|
if (sceneChanged) {
|
||||||
_lastSceneChangeTime = GetLastSceneChangeTime();
|
_lastSceneChangeTime = switcher->lastSceneChangeTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (_type) {
|
switch (_type) {
|
||||||
@@ -94,14 +95,14 @@ bool MacroConditionScene::CheckCondition()
|
|||||||
return scene == _scene.GetScene(false);
|
return scene == _scene.GetScene(false);
|
||||||
}
|
}
|
||||||
case Type::CHANGED:
|
case Type::CHANGED:
|
||||||
SetVariableValue(GetWeakSourceName(GetCurrentScene()));
|
SetVariableValue(GetWeakSourceName(switcher->currentScene));
|
||||||
SetTempVarValue("current",
|
SetTempVarValue("current",
|
||||||
GetWeakSourceName(GetCurrentScene()));
|
GetWeakSourceName(switcher->currentScene));
|
||||||
return sceneChanged;
|
return sceneChanged;
|
||||||
case Type::NOT_CHANGED:
|
case Type::NOT_CHANGED:
|
||||||
SetVariableValue(GetWeakSourceName(GetCurrentScene()));
|
SetVariableValue(GetWeakSourceName(switcher->currentScene));
|
||||||
SetTempVarValue("current",
|
SetTempVarValue("current",
|
||||||
GetWeakSourceName(GetCurrentScene()));
|
GetWeakSourceName(switcher->currentScene));
|
||||||
return !sceneChanged;
|
return !sceneChanged;
|
||||||
case Type::CURRENT_PATTERN: {
|
case Type::CURRENT_PATTERN: {
|
||||||
auto scene = getCurrentSceneHelper(_useTransitionTargetScene);
|
auto scene = getCurrentSceneHelper(_useTransitionTargetScene);
|
||||||
@@ -188,8 +189,8 @@ bool MacroConditionScene::Load(obs_data_t *obj)
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
blog(LOG_WARNING,
|
blog(LOG_WARNING,
|
||||||
"failed to convert scene condition type (%d)",
|
"failed to convert scene condition type (%d) for macro %s",
|
||||||
oldType);
|
oldType, GetMacro()->Name().c_str());
|
||||||
_type = Type::CURRENT;
|
_type = Type::CURRENT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "macro-condition-streaming.hpp"
|
#include "macro-condition-streaming.hpp"
|
||||||
|
#include "switcher-data.hpp"
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
@@ -24,32 +25,6 @@ const static std::map<MacroConditionStream::Condition, std::string>
|
|||||||
"AdvSceneSwitcher.condition.stream.state.keyFrameInterval"},
|
"AdvSceneSwitcher.condition.stream.state.keyFrameInterval"},
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool setupStreamingEventHandler();
|
|
||||||
static bool steamingEventHandlerIsSetup = setupStreamingEventHandler();
|
|
||||||
static std::chrono::high_resolution_clock::time_point streamStartTime{};
|
|
||||||
static std::chrono::high_resolution_clock::time_point streamStopTime{};
|
|
||||||
|
|
||||||
bool setupStreamingEventHandler()
|
|
||||||
{
|
|
||||||
static auto handleStreamingEvents = [](enum obs_frontend_event event,
|
|
||||||
void *) {
|
|
||||||
switch (event) {
|
|
||||||
case OBS_FRONTEND_EVENT_STREAMING_STARTING:
|
|
||||||
streamStartTime =
|
|
||||||
std::chrono::high_resolution_clock::now();
|
|
||||||
break;
|
|
||||||
case OBS_FRONTEND_EVENT_STREAMING_STOPPING:
|
|
||||||
streamStopTime =
|
|
||||||
std::chrono::high_resolution_clock::now();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
obs_frontend_add_event_callback(handleStreamingEvents, nullptr);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int MacroConditionStream::GetKeyFrameInterval()
|
int MacroConditionStream::GetKeyFrameInterval()
|
||||||
{
|
{
|
||||||
const auto configPath = GetPathInProfileDir("streamEncoder.json");
|
const auto configPath = GetPathInProfileDir("streamEncoder.json");
|
||||||
@@ -67,8 +42,10 @@ bool MacroConditionStream::CheckCondition()
|
|||||||
{
|
{
|
||||||
bool match = false;
|
bool match = false;
|
||||||
|
|
||||||
bool streamStarting = streamStartTime != _lastStreamStartingTime;
|
bool streamStarting = switcher->lastStreamStartingTime !=
|
||||||
bool streamStopping = streamStopTime != _lastStreamStoppingTime;
|
_lastStreamStartingTime;
|
||||||
|
bool streamStopping = switcher->lastStreamStoppingTime !=
|
||||||
|
_lastStreamStoppingTime;
|
||||||
|
|
||||||
switch (_condition) {
|
switch (_condition) {
|
||||||
case Condition::STOP:
|
case Condition::STOP:
|
||||||
@@ -91,10 +68,10 @@ bool MacroConditionStream::CheckCondition()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (streamStarting) {
|
if (streamStarting) {
|
||||||
_lastStreamStartingTime = streamStartTime;
|
_lastStreamStartingTime = switcher->lastStreamStartingTime;
|
||||||
}
|
}
|
||||||
if (streamStopping) {
|
if (streamStopping) {
|
||||||
_lastStreamStoppingTime = streamStopTime;
|
_lastStreamStoppingTime = switcher->lastStreamStoppingTime;
|
||||||
}
|
}
|
||||||
return match;
|
return match;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "macro-condition-transition.hpp"
|
#include "macro-condition-transition.hpp"
|
||||||
#include "scene-switch-helpers.hpp"
|
#include "switcher-data.hpp"
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
@@ -50,8 +50,8 @@ static bool isTargetScene(OBSWeakSource &target)
|
|||||||
bool MacroConditionTransition::CheckCondition()
|
bool MacroConditionTransition::CheckCondition()
|
||||||
{
|
{
|
||||||
bool anyTransitionEnded = _lastTransitionEndTime !=
|
bool anyTransitionEnded = _lastTransitionEndTime !=
|
||||||
GetLastTransitionEndTime();
|
switcher->lastTransitionEndTime;
|
||||||
bool anyTransitionStarted = AnySceneTransitionStarted();
|
bool anyTransitionStarted = switcher->AnySceneTransitionStarted();
|
||||||
bool transitionStarted = false;
|
bool transitionStarted = false;
|
||||||
bool transitionEnded = false;
|
bool transitionEnded = false;
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ bool MacroConditionTransition::CheckCondition()
|
|||||||
break;
|
break;
|
||||||
case TransitionCondition::TRANSITION_SOURCE:
|
case TransitionCondition::TRANSITION_SOURCE:
|
||||||
ret = anyTransitionStarted &&
|
ret = anyTransitionStarted &&
|
||||||
_scene.GetScene() == GetCurrentScene();
|
_scene.GetScene() == switcher->currentScene;
|
||||||
break;
|
break;
|
||||||
case TransitionCondition::TRANSITION_TARGET: {
|
case TransitionCondition::TRANSITION_TARGET: {
|
||||||
auto scene = _scene.GetScene();
|
auto scene = _scene.GetScene();
|
||||||
@@ -101,7 +101,7 @@ bool MacroConditionTransition::CheckCondition()
|
|||||||
_ended = false;
|
_ended = false;
|
||||||
}
|
}
|
||||||
if (anyTransitionEnded) {
|
if (anyTransitionEnded) {
|
||||||
_lastTransitionEndTime = GetLastTransitionEndTime();
|
_lastTransitionEndTime = switcher->lastTransitionEndTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "macro-condition-websocket.hpp"
|
#include "macro-condition-websocket.hpp"
|
||||||
|
#include "switcher-data.hpp"
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
|
|
||||||
#include <regex>
|
#include <regex>
|
||||||
@@ -33,24 +34,28 @@ static bool matchRegex(const RegexConfig &conf, const std::string &msg,
|
|||||||
|
|
||||||
bool MacroConditionWebsocket::CheckCondition()
|
bool MacroConditionWebsocket::CheckCondition()
|
||||||
{
|
{
|
||||||
std::vector<std::string> messages;
|
const std::vector<std::string> *messages = nullptr;
|
||||||
switch (_type) {
|
switch (_type) {
|
||||||
case MacroConditionWebsocket::Type::REQUEST:
|
case MacroConditionWebsocket::Type::REQUEST:
|
||||||
messages = GetWebsocketMessages();
|
messages = &switcher->websocketMessages;
|
||||||
break;
|
break;
|
||||||
case MacroConditionWebsocket::Type::EVENT: {
|
case MacroConditionWebsocket::Type::EVENT: {
|
||||||
auto connection = _connection.lock();
|
auto connection = _connection.lock();
|
||||||
if (!connection) {
|
if (!connection) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
messages = connection->Events();
|
messages = &connection->Events();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &msg : messages) {
|
if (!messages) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &msg : *messages) {
|
||||||
if (_regex.Enabled()) {
|
if (_regex.Enabled()) {
|
||||||
if (matchRegex(_regex, msg, _message)) {
|
if (matchRegex(_regex, msg, _message)) {
|
||||||
SetVariableValue(msg);
|
SetVariableValue(msg);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "macro-condition-window.hpp"
|
#include "macro-condition-window.hpp"
|
||||||
#include "plugin-state-helpers.hpp"
|
#include "switcher-data.hpp"
|
||||||
#include "platform-funcs.hpp"
|
#include "platform-funcs.hpp"
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
|
|
||||||
@@ -43,8 +43,7 @@ static bool windowContainsText(const std::string &window,
|
|||||||
bool MacroConditionWindow::WindowMatchesRequirements(
|
bool MacroConditionWindow::WindowMatchesRequirements(
|
||||||
const std::string &window) const
|
const std::string &window) const
|
||||||
{
|
{
|
||||||
const bool focusCheckOK =
|
const bool focusCheckOK = (!_focus || window == switcher->currentTitle);
|
||||||
(!_focus || window == ForegroundWindowTitle());
|
|
||||||
if (!focusCheckOK) {
|
if (!focusCheckOK) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -105,13 +104,13 @@ void MacroConditionWindow::SetVariableValueBasedOnMatch(
|
|||||||
auto text = GetTextInWindow(matchWindow);
|
auto text = GetTextInWindow(matchWindow);
|
||||||
SetVariableValue(text.value_or(""));
|
SetVariableValue(text.value_or(""));
|
||||||
} else {
|
} else {
|
||||||
SetVariableValue(ForegroundWindowTitle());
|
SetVariableValue(switcher->currentTitle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool foregroundWindowChanged()
|
static bool foregroundWindowChanged()
|
||||||
{
|
{
|
||||||
return ForegroundWindowTitle() != PreviousForegroundWindowTitle();
|
return switcher->currentTitle != switcher->lastTitle;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroConditionWindow::CheckCondition()
|
bool MacroConditionWindow::CheckCondition()
|
||||||
@@ -177,7 +176,6 @@ std::string MacroConditionWindow::GetShortDesc() const
|
|||||||
|
|
||||||
void MacroConditionWindow::SetupTempVars()
|
void MacroConditionWindow::SetupTempVars()
|
||||||
{
|
{
|
||||||
MacroCondition::SetupTempVars();
|
|
||||||
AddTempvar(
|
AddTempvar(
|
||||||
"window",
|
"window",
|
||||||
obs_module_text("AdvSceneSwitcher.tempVar.window.window"),
|
obs_module_text("AdvSceneSwitcher.tempVar.window.window"),
|
||||||
@@ -433,7 +431,7 @@ void MacroConditionWindowEdit::WindowFocusChanged(int state)
|
|||||||
|
|
||||||
void MacroConditionWindowEdit::UpdateFocusWindow()
|
void MacroConditionWindowEdit::UpdateFocusWindow()
|
||||||
{
|
{
|
||||||
_focusWindow->setText(QString::fromStdString(ForegroundWindowTitle()));
|
_focusWindow->setText(QString::fromStdString(switcher->currentTitle));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionWindowEdit::SetWidgetVisibility()
|
void MacroConditionWindowEdit::SetWidgetVisibility()
|
||||||
|
|||||||
@@ -1,59 +0,0 @@
|
|||||||
#include "macro-helpers.hpp"
|
|
||||||
#include "plugin-state-helpers.hpp"
|
|
||||||
|
|
||||||
namespace advss {
|
|
||||||
|
|
||||||
static std::atomic_bool abortMacroWait = {false};
|
|
||||||
static std::atomic_bool macroSceneSwitched = {false};
|
|
||||||
static std::atomic_int shutdownConditionCount = {0};
|
|
||||||
|
|
||||||
std::condition_variable &GetMacroWaitCV()
|
|
||||||
{
|
|
||||||
static std::condition_variable cv;
|
|
||||||
return cv;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::condition_variable &GetMacroTransitionCV()
|
|
||||||
{
|
|
||||||
static std::condition_variable cv;
|
|
||||||
return cv;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::atomic_bool &MacroWaitShouldAbort()
|
|
||||||
{
|
|
||||||
return abortMacroWait;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetMacroAbortWait(bool value)
|
|
||||||
{
|
|
||||||
abortMacroWait = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ShutdownCheckIsNecessary()
|
|
||||||
{
|
|
||||||
return shutdownConditionCount > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::atomic_int &GetShutdownConditionCount()
|
|
||||||
{
|
|
||||||
return shutdownConditionCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetMacroSwitchedScene(bool value)
|
|
||||||
{
|
|
||||||
static bool setupDone = false;
|
|
||||||
if (!setupDone) {
|
|
||||||
// Will always be called with switcher lock already held
|
|
||||||
AddIntervalResetStep([]() { macroSceneSwitched = false; },
|
|
||||||
false);
|
|
||||||
setupDone = true;
|
|
||||||
}
|
|
||||||
macroSceneSwitched = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MacroSwitchedScene()
|
|
||||||
{
|
|
||||||
return macroSceneSwitched;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace advss
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <atomic>
|
|
||||||
#include <condition_variable>
|
|
||||||
#include <string_view>
|
|
||||||
|
|
||||||
namespace advss {
|
|
||||||
|
|
||||||
constexpr std::string_view GetSceneSwitchActionId()
|
|
||||||
{
|
|
||||||
return "scene_switch";
|
|
||||||
}
|
|
||||||
std::condition_variable &GetMacroWaitCV();
|
|
||||||
std::condition_variable &GetMacroTransitionCV();
|
|
||||||
std::atomic_bool &MacroWaitShouldAbort();
|
|
||||||
void SetMacroAbortWait(bool);
|
|
||||||
bool ShutdownCheckIsNecessary();
|
|
||||||
std::atomic_int &GetShutdownConditionCount();
|
|
||||||
void SetMacroSwitchedScene(bool value);
|
|
||||||
bool MacroSwitchedScene();
|
|
||||||
|
|
||||||
} // namespace advss
|
|
||||||
@@ -9,8 +9,6 @@
|
|||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
static MacroProperties macroProperties;
|
|
||||||
|
|
||||||
void MacroProperties::Save(obs_data_t *obj) const
|
void MacroProperties::Save(obs_data_t *obj) const
|
||||||
{
|
{
|
||||||
auto data = obs_data_create();
|
auto data = obs_data_create();
|
||||||
@@ -327,19 +325,4 @@ bool MacroPropertiesDialog::AskForSettings(QWidget *parent,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MacroProperties &GetGlobalMacroProperties()
|
|
||||||
{
|
|
||||||
return macroProperties;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SaveGlobalMacroProperties(obs_data_t *obj)
|
|
||||||
{
|
|
||||||
macroProperties.Save(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LoadGlobalMacroProperties(obs_data_t *obj)
|
|
||||||
{
|
|
||||||
macroProperties.Load(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -68,8 +68,4 @@ private:
|
|||||||
int _conditionsFalseTextRow = -1;
|
int _conditionsFalseTextRow = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
MacroProperties &GetGlobalMacroProperties();
|
|
||||||
void SaveGlobalMacroProperties(obs_data_t *obj);
|
|
||||||
void LoadGlobalMacroProperties(obs_data_t *obj);
|
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -44,28 +44,8 @@ MacroSegmentList::~MacroSegmentList()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool posIsInScrollbar(const QScrollBar *scrollbar, const QPoint &pos)
|
|
||||||
{
|
|
||||||
if (!scrollbar) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!scrollbar->isVisible()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const auto geo = scrollbar->geometry();
|
|
||||||
const auto globalGeo = QRect(scrollbar->mapToGlobal(geo.topLeft()),
|
|
||||||
scrollbar->mapToGlobal(geo.bottomRight()));
|
|
||||||
return globalGeo.contains(pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
int MacroSegmentList::GetDragIndex(const QPoint &pos)
|
int MacroSegmentList::GetDragIndex(const QPoint &pos)
|
||||||
{
|
{
|
||||||
// Don't drag widget when interacting with the scrollbars
|
|
||||||
if (posIsInScrollbar(horizontalScrollBar(), mapTo(this, pos)) ||
|
|
||||||
posIsInScrollbar(verticalScrollBar(), mapTo(this, pos))) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int idx = 0; idx < _contentLayout->count(); ++idx) {
|
for (int idx = 0; idx < _contentLayout->count(); ++idx) {
|
||||||
auto item = _contentLayout->itemAt(idx);
|
auto item = _contentLayout->itemAt(idx);
|
||||||
if (!item) {
|
if (!item) {
|
||||||
@@ -181,7 +161,7 @@ void MacroSegmentList::mousePressEvent(QMouseEvent *event)
|
|||||||
#else
|
#else
|
||||||
_dragPosition = GetDragIndex(event->globalPosition().toPoint());
|
_dragPosition = GetDragIndex(event->globalPosition().toPoint());
|
||||||
#endif
|
#endif
|
||||||
emit SelectionChanged(_dragPosition);
|
emit SelectionChagned(_dragPosition);
|
||||||
} else {
|
} else {
|
||||||
_dragPosition = -1;
|
_dragPosition = -1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ public:
|
|||||||
QVBoxLayout *ContentLayout() { return _contentLayout; }
|
QVBoxLayout *ContentLayout() { return _contentLayout; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void SelectionChanged(int idx);
|
void SelectionChagned(int idx);
|
||||||
void Reorder(int source, int target);
|
void Reorder(int source, int target);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -146,6 +146,7 @@ void MacroSegment::InvalidateTempVarValues()
|
|||||||
std::optional<const TempVariable>
|
std::optional<const TempVariable>
|
||||||
MacroSegment::GetTempVar(const std::string &id) const
|
MacroSegment::GetTempVar(const std::string &id) const
|
||||||
{
|
{
|
||||||
|
TempVariable *result = nullptr;
|
||||||
for (auto &var : _tempVariables) {
|
for (auto &var : _tempVariables) {
|
||||||
if (var.ID() == id) {
|
if (var.ID() == id) {
|
||||||
return var;
|
return var;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
// so it makes sense to include them here:
|
// so it makes sense to include them here:
|
||||||
#include "log-helper.hpp"
|
#include "log-helper.hpp"
|
||||||
#include "obs-module-helper.hpp"
|
#include "obs-module-helper.hpp"
|
||||||
#include "sync-helpers.hpp"
|
#include "sync-helper.hpp"
|
||||||
#include "temp-variable.hpp"
|
#include "temp-variable.hpp"
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "macro-selection.hpp"
|
#include "macro-selection.hpp"
|
||||||
#include "macro.hpp"
|
|
||||||
#include "advanced-scene-switcher.hpp"
|
#include "advanced-scene-switcher.hpp"
|
||||||
|
#include "switcher-data.hpp"
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
|
|
||||||
#include <QStandardItemModel>
|
#include <QStandardItemModel>
|
||||||
@@ -12,7 +12,7 @@ MacroSelection::MacroSelection(QWidget *parent)
|
|||||||
: FilterComboBox(parent,
|
: FilterComboBox(parent,
|
||||||
obs_module_text("AdvSceneSwitcher.selectMacro"))
|
obs_module_text("AdvSceneSwitcher.selectMacro"))
|
||||||
{
|
{
|
||||||
for (const auto &m : GetMacros()) {
|
for (const auto &m : switcher->macros) {
|
||||||
if (m->IsGroup()) {
|
if (m->IsGroup()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ bool AdvSceneSwitcher::AddNewMacro(std::shared_ptr<Macro> &res,
|
|||||||
}
|
}
|
||||||
|
|
||||||
res = std::make_shared<Macro>(
|
res = std::make_shared<Macro>(
|
||||||
name, GetGlobalMacroProperties()._newMacroRegisterHotkeys);
|
name, switcher->macroProperties._newMacroRegisterHotkeys);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,8 +197,8 @@ static void addGroupSubitems(std::vector<std::shared_ptr<Macro>> ¯os,
|
|||||||
subitems.reserve(group->GroupSize());
|
subitems.reserve(group->GroupSize());
|
||||||
|
|
||||||
// Find all subitems
|
// Find all subitems
|
||||||
auto allMacros = GetMacros();
|
for (auto it = switcher->macros.begin(); it < switcher->macros.end();
|
||||||
for (auto it = allMacros.begin(); it < allMacros.end(); it++) {
|
it++) {
|
||||||
if ((*it)->Name() == group->Name()) {
|
if ((*it)->Name() == group->Name()) {
|
||||||
for (uint32_t i = 1; i <= group->GroupSize(); i++) {
|
for (uint32_t i = 1; i <= group->GroupSize(); i++) {
|
||||||
subitems.emplace_back(*std::next(it, i));
|
subitems.emplace_back(*std::next(it, i));
|
||||||
@@ -235,18 +235,21 @@ void AdvSceneSwitcher::ExportMacros()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OBSDataAutoRelease data = obs_data_create();
|
auto data = obs_data_create();
|
||||||
OBSDataArrayAutoRelease macroArray = obs_data_array_create();
|
auto macroArray = obs_data_array_create();
|
||||||
for (const auto ¯o : macros) {
|
for (const auto ¯o : macros) {
|
||||||
OBSDataAutoRelease obj = obs_data_create();
|
obs_data_t *obj = obs_data_create();
|
||||||
macro->Save(obj);
|
macro->Save(obj);
|
||||||
obs_data_array_push_back(macroArray, obj);
|
obs_data_array_push_back(macroArray, obj);
|
||||||
|
obs_data_release(obj);
|
||||||
}
|
}
|
||||||
obs_data_set_array(data, "macros", macroArray);
|
obs_data_set_array(data, "macros", macroArray);
|
||||||
SaveVariables(data);
|
switcher->SaveVariables(data);
|
||||||
|
obs_data_array_release(macroArray);
|
||||||
obs_data_set_string(data, "version", g_GIT_TAG);
|
obs_data_set_string(data, "version", g_GIT_TAG);
|
||||||
auto json = obs_data_get_json(data);
|
auto json = obs_data_get_json(data);
|
||||||
QString exportString(json);
|
QString exportString(json);
|
||||||
|
obs_data_release(data);
|
||||||
|
|
||||||
MacroExportImportDialog::ExportMacros(exportString);
|
MacroExportImportDialog::ExportMacros(exportString);
|
||||||
}
|
}
|
||||||
@@ -265,9 +268,8 @@ void AdvSceneSwitcher::SetupMacroSegmentSelection(MacroSection type, int idx)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MacroSegmentList *setList = nullptr, *resetList1 = nullptr,
|
MacroSegmentList *setList, *resetList1, *resetList2;
|
||||||
*resetList2 = nullptr;
|
int *setIdx, *resetIdx1, *resetIdx2;
|
||||||
int *setIdx = nullptr, *resetIdx1 = nullptr, *resetIdx2 = nullptr;
|
|
||||||
std::deque<std::shared_ptr<MacroSegment>> segements;
|
std::deque<std::shared_ptr<MacroSegment>> segements;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@@ -382,7 +384,7 @@ static void importVariables(obs_data_t *obj)
|
|||||||
if (variableWithNameExists(var->Name())) {
|
if (variableWithNameExists(var->Name())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
GetVariables().emplace_back(var);
|
switcher->variables.emplace_back(var);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -392,8 +394,7 @@ void AdvSceneSwitcher::ImportMacros()
|
|||||||
if (!MacroExportImportDialog::ImportMacros(json)) {
|
if (!MacroExportImportDialog::ImportMacros(json)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
OBSDataAutoRelease data =
|
auto data = obs_data_create_from_json(json.toStdString().c_str());
|
||||||
obs_data_create_from_json(json.toStdString().c_str());
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
DisplayMessage(obs_module_text(
|
DisplayMessage(obs_module_text(
|
||||||
"AdvSceneSwitcher.macroTab.import.invalid"));
|
"AdvSceneSwitcher.macroTab.import.invalid"));
|
||||||
@@ -409,27 +410,28 @@ void AdvSceneSwitcher::ImportMacros()
|
|||||||
version);
|
version);
|
||||||
}
|
}
|
||||||
|
|
||||||
OBSDataArrayAutoRelease array = obs_data_get_array(data, "macros");
|
auto array = obs_data_get_array(data, "macros");
|
||||||
size_t count = obs_data_array_count(array);
|
size_t count = obs_data_array_count(array);
|
||||||
|
|
||||||
int groupSize = 0;
|
int groupSize = 0;
|
||||||
std::shared_ptr<Macro> group;
|
std::shared_ptr<Macro> group;
|
||||||
std::vector<std::shared_ptr<Macro>> importedMacros;
|
|
||||||
|
|
||||||
auto lock = LockContext();
|
auto lock = LockContext();
|
||||||
|
|
||||||
for (size_t i = 0; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
OBSDataAutoRelease array_obj = obs_data_array_item(array, i);
|
obs_data_t *array_obj = obs_data_array_item(array, i);
|
||||||
auto macro = std::make_shared<Macro>();
|
auto macro = std::make_shared<Macro>();
|
||||||
macro->Load(array_obj);
|
macro->Load(array_obj);
|
||||||
|
macro->PostLoad();
|
||||||
|
|
||||||
if (macroNameExists(macro->Name()) &&
|
if (macroNameExists(macro->Name()) &&
|
||||||
!ResolveMacroImportNameConflict(macro)) {
|
!ResolveMacroImportNameConflict(macro)) {
|
||||||
|
obs_data_release(array_obj);
|
||||||
groupSize--;
|
groupSize--;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
importedMacros.emplace_back(macro);
|
switcher->macros.emplace_back(macro);
|
||||||
GetMacros().emplace_back(macro);
|
|
||||||
if (groupSize > 0 && !macro->IsGroup()) {
|
if (groupSize > 0 && !macro->IsGroup()) {
|
||||||
Macro::PrepareMoveToGroup(group, macro);
|
Macro::PrepareMoveToGroup(group, macro);
|
||||||
groupSize--;
|
groupSize--;
|
||||||
@@ -443,14 +445,14 @@ void AdvSceneSwitcher::ImportMacros()
|
|||||||
// to the group as they come up.
|
// to the group as they come up.
|
||||||
macro->ResetGroupSize();
|
macro->ResetGroupSize();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto ¯o : importedMacros) {
|
obs_data_release(array_obj);
|
||||||
macro->PostLoad();
|
|
||||||
}
|
}
|
||||||
|
obs_data_array_release(array);
|
||||||
|
obs_data_release(data);
|
||||||
|
|
||||||
ui->macros->Reset(GetMacros(),
|
ui->macros->Reset(switcher->macros,
|
||||||
GetGlobalMacroProperties()._highlightExecuted);
|
switcher->macroProperties._highlightExecuted);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_macroName_editingFinished()
|
void AdvSceneSwitcher::on_macroName_editingFinished()
|
||||||
@@ -698,7 +700,8 @@ void AdvSceneSwitcher::MacroSelectionAboutToChange()
|
|||||||
// actions nor elseActions being visible when the condition <-> action
|
// actions nor elseActions being visible when the condition <-> action
|
||||||
// splitter is moved
|
// splitter is moved
|
||||||
if (elsePos[0] == 0 && elsePos[1] == 0) {
|
if (elsePos[0] == 0 && elsePos[1] == 0) {
|
||||||
maximizeFirstSplitterEntry(ui->macroElseActionSplitter);
|
macro->SetElseActionSplitterPosition(QList<int>()
|
||||||
|
<< 999999 << 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
macro->SetElseActionSplitterPosition(
|
macro->SetElseActionSplitterPosition(
|
||||||
@@ -729,8 +732,8 @@ void AdvSceneSwitcher::MacroSelectionChanged()
|
|||||||
|
|
||||||
void AdvSceneSwitcher::HighlightOnChange()
|
void AdvSceneSwitcher::HighlightOnChange()
|
||||||
{
|
{
|
||||||
if (!GetGlobalMacroProperties()._highlightActions &&
|
if (!switcher->macroProperties._highlightActions &&
|
||||||
!GetGlobalMacroProperties()._highlightExecuted) {
|
!switcher->macroProperties._highlightExecuted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -747,13 +750,13 @@ void AdvSceneSwitcher::HighlightOnChange()
|
|||||||
|
|
||||||
void AdvSceneSwitcher::on_macroProperties_clicked()
|
void AdvSceneSwitcher::on_macroProperties_clicked()
|
||||||
{
|
{
|
||||||
MacroProperties prop = GetGlobalMacroProperties();
|
MacroProperties prop = switcher->macroProperties;
|
||||||
bool accepted = MacroPropertiesDialog::AskForSettings(
|
bool accepted = MacroPropertiesDialog::AskForSettings(
|
||||||
this, prop, GetSelectedMacro().get());
|
this, prop, GetSelectedMacro().get());
|
||||||
if (!accepted) {
|
if (!accepted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
GetGlobalMacroProperties() = prop;
|
switcher->macroProperties = prop;
|
||||||
emit HighlightMacrosChanged(prop._highlightExecuted);
|
emit HighlightMacrosChanged(prop._highlightExecuted);
|
||||||
emit HighlightActionsChanged(prop._highlightActions);
|
emit HighlightActionsChanged(prop._highlightActions);
|
||||||
emit HighlightConditionsChanged(prop._highlightConditions);
|
emit HighlightConditionsChanged(prop._highlightConditions);
|
||||||
@@ -787,13 +790,11 @@ bool shouldRestoreSplitter(const QList<int> &pos)
|
|||||||
|
|
||||||
void AdvSceneSwitcher::SetupMacroTab()
|
void AdvSceneSwitcher::SetupMacroTab()
|
||||||
{
|
{
|
||||||
ui->macroElseActions->installEventFilter(this);
|
if (switcher->macros.size() == 0 && !switcher->disableHints) {
|
||||||
|
|
||||||
if (GetMacros().size() == 0 && !switcher->disableHints) {
|
|
||||||
addPulse = PulseWidget(ui->macroAdd, QColor(Qt::green));
|
addPulse = PulseWidget(ui->macroAdd, QColor(Qt::green));
|
||||||
}
|
}
|
||||||
ui->macros->Reset(GetMacros(),
|
ui->macros->Reset(switcher->macros,
|
||||||
GetGlobalMacroProperties()._highlightExecuted);
|
switcher->macroProperties._highlightExecuted);
|
||||||
connect(ui->macros, SIGNAL(MacroSelectionAboutToChange()), this,
|
connect(ui->macros, SIGNAL(MacroSelectionAboutToChange()), this,
|
||||||
SLOT(MacroSelectionAboutToChange()));
|
SLOT(MacroSelectionAboutToChange()));
|
||||||
connect(ui->macros, SIGNAL(MacroSelectionChanged()), this,
|
connect(ui->macros, SIGNAL(MacroSelectionChanged()), this,
|
||||||
@@ -802,21 +803,21 @@ void AdvSceneSwitcher::SetupMacroTab()
|
|||||||
|
|
||||||
ui->conditionsList->SetHelpMsg(
|
ui->conditionsList->SetHelpMsg(
|
||||||
obs_module_text("AdvSceneSwitcher.macroTab.editConditionHelp"));
|
obs_module_text("AdvSceneSwitcher.macroTab.editConditionHelp"));
|
||||||
connect(ui->conditionsList, &MacroSegmentList::SelectionChanged, this,
|
connect(ui->conditionsList, &MacroSegmentList::SelectionChagned, this,
|
||||||
&AdvSceneSwitcher::MacroConditionSelectionChanged);
|
&AdvSceneSwitcher::MacroConditionSelectionChanged);
|
||||||
connect(ui->conditionsList, &MacroSegmentList::Reorder, this,
|
connect(ui->conditionsList, &MacroSegmentList::Reorder, this,
|
||||||
&AdvSceneSwitcher::MacroConditionReorder);
|
&AdvSceneSwitcher::MacroConditionReorder);
|
||||||
|
|
||||||
ui->actionsList->SetHelpMsg(
|
ui->actionsList->SetHelpMsg(
|
||||||
obs_module_text("AdvSceneSwitcher.macroTab.editActionHelp"));
|
obs_module_text("AdvSceneSwitcher.macroTab.editActionHelp"));
|
||||||
connect(ui->actionsList, &MacroSegmentList::SelectionChanged, this,
|
connect(ui->actionsList, &MacroSegmentList::SelectionChagned, this,
|
||||||
&AdvSceneSwitcher::MacroActionSelectionChanged);
|
&AdvSceneSwitcher::MacroActionSelectionChanged);
|
||||||
connect(ui->actionsList, &MacroSegmentList::Reorder, this,
|
connect(ui->actionsList, &MacroSegmentList::Reorder, this,
|
||||||
&AdvSceneSwitcher::MacroActionReorder);
|
&AdvSceneSwitcher::MacroActionReorder);
|
||||||
|
|
||||||
ui->elseActionsList->SetHelpMsg(obs_module_text(
|
ui->elseActionsList->SetHelpMsg(obs_module_text(
|
||||||
"AdvSceneSwitcher.macroTab.editElseActionHelp"));
|
"AdvSceneSwitcher.macroTab.editElseActionHelp"));
|
||||||
connect(ui->elseActionsList, &MacroSegmentList::SelectionChanged, this,
|
connect(ui->elseActionsList, &MacroSegmentList::SelectionChagned, this,
|
||||||
&AdvSceneSwitcher::MacroElseActionSelectionChanged);
|
&AdvSceneSwitcher::MacroElseActionSelectionChanged);
|
||||||
connect(ui->elseActionsList, &MacroSegmentList::Reorder, this,
|
connect(ui->elseActionsList, &MacroSegmentList::Reorder, this,
|
||||||
&AdvSceneSwitcher::MacroElseActionReorder);
|
&AdvSceneSwitcher::MacroElseActionReorder);
|
||||||
@@ -861,8 +862,6 @@ void AdvSceneSwitcher::SetupMacroTab()
|
|||||||
SetButtonIcon(ui->conditionTop, (pathPrefix + "DoubleUp.svg").c_str());
|
SetButtonIcon(ui->conditionTop, (pathPrefix + "DoubleUp.svg").c_str());
|
||||||
SetButtonIcon(ui->conditionBottom,
|
SetButtonIcon(ui->conditionBottom,
|
||||||
(pathPrefix + "DoubleDown.svg").c_str());
|
(pathPrefix + "DoubleDown.svg").c_str());
|
||||||
SetButtonIcon(ui->toggleElseActions,
|
|
||||||
(pathPrefix + "NotEqual.svg").c_str());
|
|
||||||
|
|
||||||
// Reserve more space for macro edit area than for the macro list
|
// Reserve more space for macro edit area than for the macro list
|
||||||
ui->macroListMacroEditSplitter->setStretchFactor(0, 1);
|
ui->macroListMacroEditSplitter->setStretchFactor(0, 1);
|
||||||
@@ -989,12 +988,13 @@ void AdvSceneSwitcher::CopyMacro()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
OBSDataAutoRelease data = obs_data_create();
|
obs_data_t *data = obs_data_create();
|
||||||
macro->Save(data);
|
macro->Save(data);
|
||||||
newMacro->Load(data);
|
newMacro->Load(data);
|
||||||
newMacro->PostLoad();
|
newMacro->PostLoad();
|
||||||
newMacro->SetName(name);
|
newMacro->SetName(name);
|
||||||
Macro::PrepareMoveToGroup(macro->Parent(), newMacro);
|
Macro::PrepareMoveToGroup(macro->Parent(), newMacro);
|
||||||
|
obs_data_release(data);
|
||||||
|
|
||||||
ui->macros->Add(newMacro, macro);
|
ui->macros->Add(newMacro, macro);
|
||||||
ui->macroAdd->disconnect(addPulse);
|
ui->macroAdd->disconnect(addPulse);
|
||||||
@@ -1100,31 +1100,6 @@ void AdvSceneSwitcher::MaximizeConditions()
|
|||||||
MinimizeActions();
|
MinimizeActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_toggleElseActions_clicked()
|
|
||||||
{
|
|
||||||
auto elsePosition = ui->macroElseActionSplitter->sizes();
|
|
||||||
if (elsePosition[1] == 0) {
|
|
||||||
centerSplitterPosition(ui->macroElseActionSplitter);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
maximizeFirstSplitterEntry(ui->macroElseActionSplitter);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdvSceneSwitcher::SetElseActionsStateToHidden()
|
|
||||||
{
|
|
||||||
ui->toggleElseActions->setToolTip(obs_module_text(
|
|
||||||
"AdvSceneSwitcher.macroTab.toggleElseActions.show.tooltip"));
|
|
||||||
ui->toggleElseActions->setChecked(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdvSceneSwitcher::SetElseActionsStateToVisible()
|
|
||||||
{
|
|
||||||
ui->toggleElseActions->setToolTip(obs_module_text(
|
|
||||||
"AdvSceneSwitcher.macroTab.toggleElseActions.hide.tooltip"));
|
|
||||||
ui->toggleElseActions->setChecked(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AdvSceneSwitcher::MacroTabIsInFocus()
|
bool AdvSceneSwitcher::MacroTabIsInFocus()
|
||||||
{
|
{
|
||||||
return isActiveWindow() && isAncestorOf(focusWidget()) &&
|
return isActiveWindow() && isAncestorOf(focusWidget()) &&
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#include "macro-tree.hpp"
|
#include "macro-tree.hpp"
|
||||||
#include "macro.hpp"
|
#include "macro.hpp"
|
||||||
#include "sync-helpers.hpp"
|
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
|
#include "switcher-data.hpp"
|
||||||
|
|
||||||
#include <obs.h>
|
#include <obs.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -395,7 +395,7 @@ CountItemsVisibleInModel(const std::deque<std::shared_ptr<Macro>> ¯os)
|
|||||||
|
|
||||||
void MacroTreeModel::Add(std::shared_ptr<Macro> item)
|
void MacroTreeModel::Add(std::shared_ptr<Macro> item)
|
||||||
{
|
{
|
||||||
auto lock = LockContext();
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
auto idx = CountItemsVisibleInModel(_macros);
|
auto idx = CountItemsVisibleInModel(_macros);
|
||||||
beginInsertRows(QModelIndex(), idx, idx);
|
beginInsertRows(QModelIndex(), idx, idx);
|
||||||
_macros.emplace_back(item);
|
_macros.emplace_back(item);
|
||||||
@@ -408,7 +408,7 @@ void MacroTreeModel::Add(std::shared_ptr<Macro> item)
|
|||||||
|
|
||||||
void MacroTreeModel::Remove(std::shared_ptr<Macro> item)
|
void MacroTreeModel::Remove(std::shared_ptr<Macro> item)
|
||||||
{
|
{
|
||||||
auto lock = LockContext();
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
auto uiStartIdx = GetItemModelIndex(item);
|
auto uiStartIdx = GetItemModelIndex(item);
|
||||||
if (uiStartIdx == -1) {
|
if (uiStartIdx == -1) {
|
||||||
return;
|
return;
|
||||||
@@ -643,7 +643,7 @@ void MacroTreeModel::GroupSelectedItems(QModelIndexList &indices)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lock = LockContext();
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
QString name = GetNewGroupName();
|
QString name = GetNewGroupName();
|
||||||
std::vector<std::shared_ptr<Macro>> itemsToGroup;
|
std::vector<std::shared_ptr<Macro>> itemsToGroup;
|
||||||
itemsToGroup.reserve(indices.size());
|
itemsToGroup.reserve(indices.size());
|
||||||
@@ -691,7 +691,7 @@ void MacroTreeModel::UngroupSelectedGroups(QModelIndexList &indices)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lock = LockContext();
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
for (int i = indices.count() - 1; i >= 0; i--) {
|
for (int i = indices.count() - 1; i >= 0; i--) {
|
||||||
std::shared_ptr<Macro> item = _macros[ModelIndexToMacroIndex(
|
std::shared_ptr<Macro> item = _macros[ModelIndexToMacroIndex(
|
||||||
indices[i].row(), _macros)];
|
indices[i].row(), _macros)];
|
||||||
@@ -1055,7 +1055,7 @@ void MacroTree::dropEvent(QDropEvent *event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Move items in backend
|
// Move items in backend
|
||||||
auto lock = LockContext();
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
int to = row;
|
int to = row;
|
||||||
try {
|
try {
|
||||||
to = ModelIndexToMacroIndex(row, items);
|
to = ModelIndexToMacroIndex(row, items);
|
||||||
@@ -1181,7 +1181,7 @@ void MacroTree::Remove(std::shared_ptr<Macro> item) const
|
|||||||
|
|
||||||
void MacroTree::Up(std::shared_ptr<Macro> item) const
|
void MacroTree::Up(std::shared_ptr<Macro> item) const
|
||||||
{
|
{
|
||||||
auto lock = LockContext();
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
auto above = GetModel()->Neighbor(item, true);
|
auto above = GetModel()->Neighbor(item, true);
|
||||||
if (!above) {
|
if (!above) {
|
||||||
return;
|
return;
|
||||||
@@ -1207,7 +1207,7 @@ void MacroTree::Up(std::shared_ptr<Macro> item) const
|
|||||||
|
|
||||||
void MacroTree::Down(std::shared_ptr<Macro> item) const
|
void MacroTree::Down(std::shared_ptr<Macro> item) const
|
||||||
{
|
{
|
||||||
auto lock = LockContext();
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
auto below = GetModel()->Neighbor(item, false);
|
auto below = GetModel()->Neighbor(item, false);
|
||||||
if (!below) {
|
if (!below) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,24 +1,20 @@
|
|||||||
#include "macro.hpp"
|
#include "macro.hpp"
|
||||||
#include "macro-action-factory.hpp"
|
#include "macro-action-edit.hpp"
|
||||||
#include "macro-condition-factory.hpp"
|
#include "macro-condition-edit.hpp"
|
||||||
#include "macro-dock.hpp"
|
#include "macro-dock.hpp"
|
||||||
#include "macro-helpers.hpp"
|
#include "macro-action-scene-switch.hpp"
|
||||||
#include "plugin-state-helpers.hpp"
|
#include "switcher-data.hpp"
|
||||||
#include "hotkey.hpp"
|
#include "hotkey.hpp"
|
||||||
#include "sync-helpers.hpp"
|
|
||||||
#include "utility.hpp"
|
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#undef max
|
#undef max
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <QAction>
|
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
static constexpr int perfLogThreshold = 300;
|
constexpr int perfLogThreshold = 300;
|
||||||
static std::deque<std::shared_ptr<Macro>> macros;
|
|
||||||
|
|
||||||
Macro::Macro(const std::string &name, const bool addHotkey)
|
Macro::Macro(const std::string &name, const bool addHotkey)
|
||||||
{
|
{
|
||||||
@@ -37,7 +33,7 @@ Macro::~Macro()
|
|||||||
|
|
||||||
// Keep the dock widgets in case of shutdown so they can be restored by
|
// Keep the dock widgets in case of shutdown so they can be restored by
|
||||||
// OBS on startup
|
// OBS on startup
|
||||||
if (!OBSIsShuttingDown()) {
|
if (!switcher->obsIsShuttingDown) {
|
||||||
RemoveDock();
|
RemoveDock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -57,8 +53,9 @@ Macro::CreateGroup(const std::string &name,
|
|||||||
|
|
||||||
void Macro::RemoveGroup(std::shared_ptr<Macro> group)
|
void Macro::RemoveGroup(std::shared_ptr<Macro> group)
|
||||||
{
|
{
|
||||||
auto it = std::find(macros.begin(), macros.end(), group);
|
auto it = std::find(switcher->macros.begin(), switcher->macros.end(),
|
||||||
if (it == macros.end()) {
|
group);
|
||||||
|
if (it == switcher->macros.end()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,12 +65,12 @@ void Macro::RemoveGroup(std::shared_ptr<Macro> group)
|
|||||||
(*m)->SetParent(nullptr);
|
(*m)->SetParent(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
macros.erase(it);
|
switcher->macros.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Macro::PrepareMoveToGroup(Macro *group, std::shared_ptr<Macro> item)
|
void Macro::PrepareMoveToGroup(Macro *group, std::shared_ptr<Macro> item)
|
||||||
{
|
{
|
||||||
for (const auto &m : macros) {
|
for (auto &m : switcher->macros) {
|
||||||
if (m.get() == group) {
|
if (m.get() == group) {
|
||||||
PrepareMoveToGroup(m, item);
|
PrepareMoveToGroup(m, item);
|
||||||
return;
|
return;
|
||||||
@@ -152,7 +149,6 @@ bool Macro::CeckMatch()
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case LogicType::OR_NOT:
|
case LogicType::OR_NOT:
|
||||||
_matched = _matched || !cond;
|
|
||||||
if (!cond) {
|
if (!cond) {
|
||||||
c->SetHighlight();
|
c->SetHighlight();
|
||||||
}
|
}
|
||||||
@@ -354,7 +350,7 @@ void Macro::AddHelperThread(std::thread &&newThread)
|
|||||||
void Macro::Stop()
|
void Macro::Stop()
|
||||||
{
|
{
|
||||||
_stop = true;
|
_stop = true;
|
||||||
GetMacroWaitCV().notify_all();
|
switcher->macroWaitCv.notify_all();
|
||||||
for (auto &t : _helperThreads) {
|
for (auto &t : _helperThreads) {
|
||||||
if (t.joinable()) {
|
if (t.joinable()) {
|
||||||
t.join();
|
t.join();
|
||||||
@@ -746,13 +742,15 @@ bool Macro::PostLoad()
|
|||||||
|
|
||||||
bool Macro::SwitchesScene() const
|
bool Macro::SwitchesScene() const
|
||||||
{
|
{
|
||||||
|
MacroActionSwitchScene temp(nullptr);
|
||||||
|
auto sceneSwitchId = temp.GetId();
|
||||||
for (const auto &a : _actions) {
|
for (const auto &a : _actions) {
|
||||||
if (a->GetId() == GetSceneSwitchActionId()) {
|
if (a->GetId() == sceneSwitchId) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const auto &a : _elseActions) {
|
for (const auto &a : _elseActions) {
|
||||||
if (a->GetId() == GetSceneSwitchActionId()) {
|
if (a->GetId() == sceneSwitchId) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -948,7 +946,7 @@ void Macro::EnableDock(bool value)
|
|||||||
// geometry set here.
|
// geometry set here.
|
||||||
// The function calls here are only intended to attempt to restore the
|
// The function calls here are only intended to attempt to restore the
|
||||||
// dock status when switching scene collections.
|
// dock status when switching scene collections.
|
||||||
if (InitialLoadIsComplete()) {
|
if (switcher->startupLoadDone) {
|
||||||
_dock->setVisible(_dockIsVisible);
|
_dock->setVisible(_dockIsVisible);
|
||||||
if (window->dockWidgetArea(_dock) != _dockArea) {
|
if (window->dockWidgetArea(_dock) != _dockArea) {
|
||||||
window->addDockWidget(_dockArea, _dock);
|
window->addDockWidget(_dockArea, _dock);
|
||||||
@@ -1164,10 +1162,12 @@ void Macro::SetHotkeysDesc() const
|
|||||||
_name, _togglePauseHotkey);
|
_name, _togglePauseHotkey);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveMacros(obs_data_t *obj)
|
void SwitcherData::SaveMacros(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
|
switcher->macroProperties.Save(obj);
|
||||||
|
|
||||||
obs_data_array_t *macroArray = obs_data_array_create();
|
obs_data_array_t *macroArray = obs_data_array_create();
|
||||||
for (const auto &m : macros) {
|
for (auto &m : macros) {
|
||||||
obs_data_t *array_obj = obs_data_create();
|
obs_data_t *array_obj = obs_data_create();
|
||||||
|
|
||||||
m->Save(array_obj);
|
m->Save(array_obj);
|
||||||
@@ -1179,9 +1179,10 @@ void SaveMacros(obs_data_t *obj)
|
|||||||
obs_data_array_release(macroArray);
|
obs_data_array_release(macroArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadMacros(obs_data_t *obj)
|
void SwitcherData::LoadMacros(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
Hotkey::ClearAllHotkeys();
|
Hotkey::ClearAllHotkeys();
|
||||||
|
switcher->macroProperties.Load(obj);
|
||||||
|
|
||||||
macros.clear();
|
macros.clear();
|
||||||
obs_data_array_t *macroArray = obs_data_get_array(obj, "macros");
|
obs_data_array_t *macroArray = obs_data_get_array(obj, "macros");
|
||||||
@@ -1198,7 +1199,7 @@ void LoadMacros(obs_data_t *obj)
|
|||||||
int groupCount = 0;
|
int groupCount = 0;
|
||||||
std::shared_ptr<Macro> group;
|
std::shared_ptr<Macro> group;
|
||||||
std::vector<std::shared_ptr<Macro>> invalidGroups;
|
std::vector<std::shared_ptr<Macro>> invalidGroups;
|
||||||
for (const auto &m : macros) {
|
for (auto &m : macros) {
|
||||||
if (groupCount && m->IsGroup()) {
|
if (groupCount && m->IsGroup()) {
|
||||||
blog(LOG_ERROR,
|
blog(LOG_ERROR,
|
||||||
"nested group detected - will delete \"%s\"",
|
"nested group detected - will delete \"%s\"",
|
||||||
@@ -1233,28 +1234,23 @@ void LoadMacros(obs_data_t *obj)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::deque<std::shared_ptr<Macro>> &GetMacros()
|
bool SwitcherData::CheckMacros()
|
||||||
{
|
{
|
||||||
return macros;
|
bool ret = false;
|
||||||
}
|
for (auto &m : macros) {
|
||||||
|
|
||||||
bool CheckMacros()
|
|
||||||
{
|
|
||||||
bool matchFound = false;
|
|
||||||
for (const auto &m : macros) {
|
|
||||||
if (m->CeckMatch() || m->ElseActions().size() > 0) {
|
if (m->CeckMatch() || m->ElseActions().size() > 0) {
|
||||||
matchFound = true;
|
ret = true;
|
||||||
// This has to be performed here for now as actions are
|
// This has to be performed here for now as actions are
|
||||||
// not performed immediately after checking conditions.
|
// not performed immediately after checking conditions.
|
||||||
if (m->SwitchesScene()) {
|
if (m->SwitchesScene()) {
|
||||||
SetMacroSwitchedScene(true);
|
switcher->macroSceneSwitched = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return matchFound;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RunMacros()
|
bool SwitcherData::RunMacros()
|
||||||
{
|
{
|
||||||
// Create copy of macro list as elements might be removed, inserted, or
|
// Create copy of macro list as elements might be removed, inserted, or
|
||||||
// reordered while macros are currently being executed.
|
// reordered while macros are currently being executed.
|
||||||
@@ -1272,16 +1268,15 @@ bool RunMacros()
|
|||||||
// the constructor of AdvSceneSwitcher() to complete.
|
// the constructor of AdvSceneSwitcher() to complete.
|
||||||
// The constructor of AdvSceneSwitcher() cannot continue however as it
|
// The constructor of AdvSceneSwitcher() cannot continue however as it
|
||||||
// cannot lock the main switcher mutex.
|
// cannot lock the main switcher mutex.
|
||||||
auto lock = GetLoopLock();
|
if (GetLock()) {
|
||||||
if (lock) {
|
GetLock()->unlock();
|
||||||
lock->unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &m : runPhaseMacros) {
|
for (auto &m : runPhaseMacros) {
|
||||||
if (!m || !m->ShouldRunActions()) {
|
if (!m || !m->ShouldRunActions()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (IsFirstInterval() && m->SkipExecOnStart()) {
|
if (firstInterval && m->SkipExecOnStart()) {
|
||||||
blog(LOG_INFO,
|
blog(LOG_INFO,
|
||||||
"skip execution of macro \"%s\" at startup",
|
"skip execution of macro \"%s\" at startup",
|
||||||
m->Name().c_str());
|
m->Name().c_str());
|
||||||
@@ -1292,15 +1287,15 @@ bool RunMacros()
|
|||||||
blog(LOG_WARNING, "abort macro: %s", m->Name().c_str());
|
blog(LOG_WARNING, "abort macro: %s", m->Name().c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (lock) {
|
if (GetLock()) {
|
||||||
lock->lock();
|
GetLock()->lock();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Macro *GetMacroByName(const char *name)
|
Macro *GetMacroByName(const char *name)
|
||||||
{
|
{
|
||||||
for (const auto &m : macros) {
|
for (auto &m : switcher->macros) {
|
||||||
if (m->Name() == name) {
|
if (m->Name() == name) {
|
||||||
return m.get();
|
return m.get();
|
||||||
}
|
}
|
||||||
@@ -1316,7 +1311,7 @@ Macro *GetMacroByQString(const QString &name)
|
|||||||
|
|
||||||
std::weak_ptr<Macro> GetWeakMacroByName(const char *name)
|
std::weak_ptr<Macro> GetWeakMacroByName(const char *name)
|
||||||
{
|
{
|
||||||
for (const auto &m : macros) {
|
for (auto &m : switcher->macros) {
|
||||||
if (m->Name() == name) {
|
if (m->Name() == name) {
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
@@ -1327,7 +1322,7 @@ std::weak_ptr<Macro> GetWeakMacroByName(const char *name)
|
|||||||
|
|
||||||
void InvalidateMacroTempVarValues()
|
void InvalidateMacroTempVarValues()
|
||||||
{
|
{
|
||||||
for (const auto &m : macros) {
|
for (auto &m : switcher->macros) {
|
||||||
m->InvalidateTempVarValues();
|
m->InvalidateTempVarValues();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -202,11 +202,6 @@ private:
|
|||||||
QAction *_dockAction = nullptr;
|
QAction *_dockAction = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
void LoadMacros(obs_data_t *obj);
|
|
||||||
void SaveMacros(obs_data_t *obj);
|
|
||||||
std::deque<std::shared_ptr<Macro>> &GetMacros();
|
|
||||||
bool CheckMacros();
|
|
||||||
bool RunMacros();
|
|
||||||
Macro *GetMacroByName(const char *name);
|
Macro *GetMacroByName(const char *name);
|
||||||
Macro *GetMacroByQString(const QString &name);
|
Macro *GetMacroByQString(const QString &name);
|
||||||
std::weak_ptr<Macro> GetWeakMacroByName(const char *name);
|
std::weak_ptr<Macro> GetWeakMacroByName(const char *name);
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ bool MacroConditionMidi::CheckCondition()
|
|||||||
|
|
||||||
for (const auto &m : *messages) {
|
for (const auto &m : *messages) {
|
||||||
if (m.Matches(_message)) {
|
if (m.Matches(_message)) {
|
||||||
SetVariableValues(m);
|
SetVariableValue(std::to_string(m.Note()) + " " +
|
||||||
|
std::to_string(m.Value()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -48,36 +49,6 @@ std::string MacroConditionMidi::GetShortDesc() const
|
|||||||
return _device.Name();
|
return _device.Name();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionMidi::SetupTempVars()
|
|
||||||
{
|
|
||||||
MacroCondition::SetupTempVars();
|
|
||||||
AddTempvar("type",
|
|
||||||
obs_module_text("AdvSceneSwitcher.tempVar.midi.type"));
|
|
||||||
AddTempvar("channel",
|
|
||||||
obs_module_text("AdvSceneSwitcher.tempVar.midi.channel"));
|
|
||||||
AddTempvar("note",
|
|
||||||
obs_module_text("AdvSceneSwitcher.tempVar.midi.note"));
|
|
||||||
AddTempvar("value1",
|
|
||||||
obs_module_text("AdvSceneSwitcher.tempVar.midi.value1"));
|
|
||||||
AddTempvar("value2",
|
|
||||||
obs_module_text("AdvSceneSwitcher.tempVar.midi.value2"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroConditionMidi::SetVariableValues(const MidiMessage &m)
|
|
||||||
{
|
|
||||||
SetVariableValue(std::to_string(m.Note()) + " " +
|
|
||||||
std::to_string(m.Value()));
|
|
||||||
SetTempVarValue("type", m.MidiTypeToString(m.Type()));
|
|
||||||
SetTempVarValue("channel", std::to_string(m.Channel()));
|
|
||||||
try {
|
|
||||||
SetTempVarValue("note",
|
|
||||||
GetAllNotes().at(m.Note()).toStdString());
|
|
||||||
} catch (...) {
|
|
||||||
}
|
|
||||||
SetTempVarValue("value1", std::to_string(m.Note()));
|
|
||||||
SetTempVarValue("value2", std::to_string(m.Value()));
|
|
||||||
}
|
|
||||||
|
|
||||||
MacroConditionMidiEdit::MacroConditionMidiEdit(
|
MacroConditionMidiEdit::MacroConditionMidiEdit(
|
||||||
QWidget *parent, std::shared_ptr<MacroConditionMidi> entryData)
|
QWidget *parent, std::shared_ptr<MacroConditionMidi> entryData)
|
||||||
: QWidget(parent),
|
: QWidget(parent),
|
||||||
|
|||||||
@@ -24,9 +24,6 @@ public:
|
|||||||
MidiMessage _message;
|
MidiMessage _message;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SetupTempVars();
|
|
||||||
void SetVariableValues(const MidiMessage &);
|
|
||||||
|
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
static const std::string id;
|
static const std::string id;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,17 +1,15 @@
|
|||||||
#include "midi-helpers.hpp"
|
#include "midi-helpers.hpp"
|
||||||
|
|
||||||
#include <utility.hpp>
|
#include <utility.hpp>
|
||||||
#include <log-helper.hpp>
|
|
||||||
#include <obs-module-helper.hpp>
|
#include <obs-module-helper.hpp>
|
||||||
#include <plugin-state-helpers.hpp>
|
#include <switcher-data.hpp>
|
||||||
#include <sync-helpers.hpp>
|
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
static std::map<std::pair<MidiDeviceType, int>, MidiDeviceInstance *>
|
static std::map<std::pair<MidiDeviceType, int>, MidiDeviceInstance *>
|
||||||
SetupMidiMessageVector()
|
SetupMidiMessageVector()
|
||||||
{
|
{
|
||||||
AddIntervalResetStep(
|
GetSwitcher()->AddIntervalResetStep(
|
||||||
MidiDeviceInstance::ClearMessageBuffersOfAllDevices);
|
MidiDeviceInstance::ClearMessageBuffersOfAllDevices);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ void CategoryGrabber::Search(const std::string &)
|
|||||||
std::string cursor;
|
std::string cursor;
|
||||||
httplib::Params params = {
|
httplib::Params params = {
|
||||||
{"first", "100"}, {"after", cursor}, {"query", _searchString}};
|
{"first", "100"}, {"after", cursor}, {"query", _searchString}};
|
||||||
auto response = SendGetRequest(*_token, uri, path, params);
|
auto response = SendGetRequest(uri, path, *_token, params);
|
||||||
|
|
||||||
while (response.status == 200 && !_stop) {
|
while (response.status == 200 && !_stop) {
|
||||||
cursor = ParseReply(response.data);
|
cursor = ParseReply(response.data);
|
||||||
@@ -200,7 +200,7 @@ void CategoryGrabber::Search(const std::string &)
|
|||||||
params = {{"first", "100"},
|
params = {{"first", "100"},
|
||||||
{"after", cursor},
|
{"after", cursor},
|
||||||
{"query", _searchString}};
|
{"query", _searchString}};
|
||||||
response = SendGetRequest(*_token, uri, path, params);
|
response = SendGetRequest(uri, path, *_token, params);
|
||||||
emit CategoryCountUpdated(_categoryMap.size() - startCount);
|
emit CategoryCountUpdated(_categoryMap.size() - startCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -214,7 +214,7 @@ void CategoryGrabber::GetAll()
|
|||||||
static std::string cursor;
|
static std::string cursor;
|
||||||
|
|
||||||
httplib::Params params = {{"first", "100"}, {"after", cursor}};
|
httplib::Params params = {{"first", "100"}, {"after", cursor}};
|
||||||
auto response = SendGetRequest(*_token, uri, path, params);
|
auto response = SendGetRequest(uri, path, *_token, params);
|
||||||
|
|
||||||
while (response.status == 200 && !_stop) {
|
while (response.status == 200 && !_stop) {
|
||||||
cursor = ParseReply(response.data);
|
cursor = ParseReply(response.data);
|
||||||
@@ -222,7 +222,7 @@ void CategoryGrabber::GetAll()
|
|||||||
break; // End of category list
|
break; // End of category list
|
||||||
}
|
}
|
||||||
params = {{"first", "100"}, {"after", cursor}};
|
params = {{"first", "100"}, {"after", cursor}};
|
||||||
response = SendGetRequest(*_token, uri, path, params);
|
response = SendGetRequest(uri, path, *_token, params);
|
||||||
emit CategoryCountUpdated(_categoryMap.size());
|
emit CategoryCountUpdated(_categoryMap.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ std::string TwitchChannel::GetUserID(const TwitchToken &token) const
|
|||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto res = SendGetRequest(token, "https://api.twitch.tv",
|
auto res = SendGetRequest("https://api.twitch.tv", "/helix/users",
|
||||||
"/helix/users", {{"login", _name}});
|
token, {{"login", _name}});
|
||||||
|
|
||||||
if (res.status == 400) {
|
if (res.status == 400) {
|
||||||
userIDCache[_name] = "invalid";
|
userIDCache[_name] = "invalid";
|
||||||
@@ -112,8 +112,8 @@ TwitchChannel::GetLiveInfo(const TwitchToken &token)
|
|||||||
|
|
||||||
httplib::Params params = {
|
httplib::Params params = {
|
||||||
{"first", "1"}, {"after", ""}, {"user_id", id}};
|
{"first", "1"}, {"after", ""}, {"user_id", id}};
|
||||||
auto result = SendGetRequest(token, "https://api.twitch.tv",
|
auto result = SendGetRequest("https://api.twitch.tv", "/helix/streams",
|
||||||
"/helix/streams", params, true);
|
token, params, true);
|
||||||
if (result.status != 200) {
|
if (result.status != 200) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -153,8 +153,8 @@ std::optional<ChannelInfo> TwitchChannel::GetInfo(const TwitchToken &token)
|
|||||||
|
|
||||||
httplib::Params params = {
|
httplib::Params params = {
|
||||||
{"first", "1"}, {"after", ""}, {"broadcaster_id", id}};
|
{"first", "1"}, {"after", ""}, {"broadcaster_id", id}};
|
||||||
auto result = SendGetRequest(token, "https://api.twitch.tv",
|
auto result = SendGetRequest("https://api.twitch.tv", "/helix/channels",
|
||||||
"/helix/channels", params, true);
|
token, params, true);
|
||||||
if (result.status != 200) {
|
if (result.status != 200) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
#include "twitch-helpers.hpp"
|
#include "twitch-helpers.hpp"
|
||||||
|
|
||||||
#include <log-helper.hpp>
|
#include <log-helper.hpp>
|
||||||
#include <plugin-state-helpers.hpp>
|
#include <switcher-data.hpp>
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
@@ -364,7 +364,8 @@ TwitchChatConnection::~TwitchChatConnection()
|
|||||||
|
|
||||||
static bool setupChatMessageClear()
|
static bool setupChatMessageClear()
|
||||||
{
|
{
|
||||||
AddIntervalResetStep(&TwitchChatConnection::ClearAllMessages);
|
GetSwitcher()->AddIntervalResetStep(
|
||||||
|
&TwitchChatConnection::ClearAllMessages);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -431,8 +432,8 @@ void TwitchChatConnection::ConnectThread()
|
|||||||
_client.reset();
|
_client.reset();
|
||||||
_connected = true;
|
_connected = true;
|
||||||
websocketpp::lib::error_code ec;
|
websocketpp::lib::error_code ec;
|
||||||
websocketpp::client<websocketpp::config::asio_tls_client>::
|
EventSubWSClient::connection_ptr con =
|
||||||
connection_ptr con = _client.get_connection(_url, ec);
|
_client.get_connection(_url, ec);
|
||||||
if (ec) {
|
if (ec) {
|
||||||
blog(LOG_INFO, "Twitch TwitchChatConnection failed: %s",
|
blog(LOG_INFO, "Twitch TwitchChatConnection failed: %s",
|
||||||
ec.message().c_str());
|
ec.message().c_str());
|
||||||
@@ -633,10 +634,8 @@ void TwitchChatConnection::OnOpen(connection_hdl)
|
|||||||
Authenticate();
|
Authenticate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TwitchChatConnection::OnMessage(
|
void TwitchChatConnection::OnMessage(connection_hdl,
|
||||||
connection_hdl,
|
EventSubWSClient::message_ptr message)
|
||||||
websocketpp::client<websocketpp::config::asio_tls_client>::message_ptr
|
|
||||||
message)
|
|
||||||
{
|
{
|
||||||
constexpr std::string_view authOKCommand = "001";
|
constexpr std::string_view authOKCommand = "001";
|
||||||
constexpr std::string_view pingCommand = "PING";
|
constexpr std::string_view pingCommand = "PING";
|
||||||
@@ -680,8 +679,7 @@ void TwitchChatConnection::OnMessage(
|
|||||||
|
|
||||||
void TwitchChatConnection::OnClose(connection_hdl hdl)
|
void TwitchChatConnection::OnClose(connection_hdl hdl)
|
||||||
{
|
{
|
||||||
websocketpp::client<websocketpp::config::asio_tls_client>::connection_ptr
|
EventSubWSClient::connection_ptr con = _client.get_con_from_hdl(hdl);
|
||||||
con = _client.get_con_from_hdl(hdl);
|
|
||||||
auto msg = con->get_ec().message();
|
auto msg = con->get_ec().message();
|
||||||
blog(LOG_INFO, "Twitch chat connection closed: %s", msg.c_str());
|
blog(LOG_INFO, "Twitch chat connection closed: %s", msg.c_str());
|
||||||
_connected = false;
|
_connected = false;
|
||||||
@@ -689,8 +687,7 @@ void TwitchChatConnection::OnClose(connection_hdl hdl)
|
|||||||
|
|
||||||
void TwitchChatConnection::OnFail(connection_hdl hdl)
|
void TwitchChatConnection::OnFail(connection_hdl hdl)
|
||||||
{
|
{
|
||||||
websocketpp::client<websocketpp::config::asio_tls_client>::connection_ptr
|
EventSubWSClient::connection_ptr con = _client.get_con_from_hdl(hdl);
|
||||||
con = _client.get_con_from_hdl(hdl);
|
|
||||||
auto msg = con->get_ec().message();
|
auto msg = con->get_ec().message();
|
||||||
blog(LOG_INFO, "Twitch chat connection failed: %s", msg.c_str());
|
blog(LOG_INFO, "Twitch chat connection failed: %s", msg.c_str());
|
||||||
_connected = false;
|
_connected = false;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
#include "twitch-helpers.hpp"
|
#include "twitch-helpers.hpp"
|
||||||
|
|
||||||
#include <log-helper.hpp>
|
#include <log-helper.hpp>
|
||||||
#include <plugin-state-helpers.hpp>
|
#include <switcher-data.hpp>
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ EventSub::~EventSub()
|
|||||||
|
|
||||||
static bool setupEventSubMessageClear()
|
static bool setupEventSubMessageClear()
|
||||||
{
|
{
|
||||||
AddIntervalResetStep(&EventSub::ClearAllEvents);
|
GetSwitcher()->AddIntervalResetStep(&EventSub::ClearAllEvents);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,16 +230,14 @@ std::string EventSub::AddEventSubscribtion(std::shared_ptr<TwitchToken> token,
|
|||||||
|
|
||||||
OBSDataAutoRelease postData = copyData(subscription.data);
|
OBSDataAutoRelease postData = copyData(subscription.data);
|
||||||
setTransportData(postData.Get(), eventSub->_sessionID);
|
setTransportData(postData.Get(), eventSub->_sessionID);
|
||||||
auto result = SendPostRequest(*token, registerSubscriptionURL.data(),
|
auto result = SendPostRequest(registerSubscriptionURL.data(),
|
||||||
registerSubscriptionPath.data(), {},
|
registerSubscriptionPath.data(), *token,
|
||||||
postData.Get());
|
postData.Get());
|
||||||
|
|
||||||
if (result.status != 202) {
|
if (result.status != 202) {
|
||||||
vblog(LOG_INFO, "failed to register Twitch EventSub (%d)",
|
vblog(LOG_INFO, "failed to register Twitch EventSub (%d)",
|
||||||
result.status);
|
result.status);
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
OBSDataArrayAutoRelease replyArray =
|
OBSDataArrayAutoRelease replyArray =
|
||||||
obs_data_get_array(result.data, "data");
|
obs_data_get_array(result.data, "data");
|
||||||
OBSDataAutoRelease replyData = obs_data_array_item(replyArray, 0);
|
OBSDataAutoRelease replyData = obs_data_array_item(replyArray, 0);
|
||||||
|
|||||||
@@ -19,24 +19,24 @@ std::string MacroActionTwitch::GetShortDesc() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
const static std::map<MacroActionTwitch::Action, std::string> actionTypes = {
|
const static std::map<MacroActionTwitch::Action, std::string> actionTypes = {
|
||||||
{MacroActionTwitch::Action::CHANNEL_INFO_TITLE_SET,
|
{MacroActionTwitch::Action::TITLE,
|
||||||
"AdvSceneSwitcher.action.twitch.type.channel.info.title.set"},
|
"AdvSceneSwitcher.action.twitch.type.title"},
|
||||||
{MacroActionTwitch::Action::CHANNEL_INFO_CATEGORY_SET,
|
{MacroActionTwitch::Action::CATEGORY,
|
||||||
"AdvSceneSwitcher.action.twitch.type.channel.info.category.set"},
|
"AdvSceneSwitcher.action.twitch.type.category"},
|
||||||
{MacroActionTwitch::Action::RAID_START,
|
{MacroActionTwitch::Action::MARKER,
|
||||||
"AdvSceneSwitcher.action.twitch.type.raid.start"},
|
"AdvSceneSwitcher.action.twitch.type.marker"},
|
||||||
{MacroActionTwitch::Action::COMMERCIAL_START,
|
{MacroActionTwitch::Action::CLIP,
|
||||||
"AdvSceneSwitcher.action.twitch.type.commercial.start"},
|
"AdvSceneSwitcher.action.twitch.type.clip"},
|
||||||
{MacroActionTwitch::Action::MARKER_CREATE,
|
{MacroActionTwitch::Action::COMMERCIAL,
|
||||||
"AdvSceneSwitcher.action.twitch.type.marker.create"},
|
"AdvSceneSwitcher.action.twitch.type.commercial"},
|
||||||
{MacroActionTwitch::Action::CLIP_CREATE,
|
{MacroActionTwitch::Action::ANNOUNCEMENT,
|
||||||
"AdvSceneSwitcher.action.twitch.type.clip.create"},
|
"AdvSceneSwitcher.action.twitch.type.announcement"},
|
||||||
{MacroActionTwitch::Action::CHAT_ANNOUNCEMENT_SEND,
|
{MacroActionTwitch::Action::ENABLE_EMOTE_ONLY,
|
||||||
"AdvSceneSwitcher.action.twitch.type.chat.announcement.send"},
|
"AdvSceneSwitcher.action.twitch.type.emoteOnlyEnable"},
|
||||||
{MacroActionTwitch::Action::CHAT_EMOTE_ONLY_ENABLE,
|
{MacroActionTwitch::Action::DISABLE_EMOTE_ONLY,
|
||||||
"AdvSceneSwitcher.action.twitch.type.chat.emoteOnly.enable"},
|
"AdvSceneSwitcher.action.twitch.type.emoteOnlyDisable"},
|
||||||
{MacroActionTwitch::Action::CHAT_EMOTE_ONLY_DISABLE,
|
{MacroActionTwitch::Action::RAID,
|
||||||
"AdvSceneSwitcher.action.twitch.type.chat.emoteOnly.disable"},
|
"AdvSceneSwitcher.action.twitch.type.raid"},
|
||||||
{MacroActionTwitch::Action::SEND_CHAT_MESSAGE,
|
{MacroActionTwitch::Action::SEND_CHAT_MESSAGE,
|
||||||
"AdvSceneSwitcher.action.twitch.type.sendChatMessage"},
|
"AdvSceneSwitcher.action.twitch.type.sendChatMessage"},
|
||||||
};
|
};
|
||||||
@@ -64,12 +64,6 @@ const static std::map<MacroActionTwitch::AnnouncementColor, std::string>
|
|||||||
{MacroActionTwitch::AnnouncementColor::PURPLE, "purple"},
|
{MacroActionTwitch::AnnouncementColor::PURPLE, "purple"},
|
||||||
};
|
};
|
||||||
|
|
||||||
const static std::map<MacroActionTwitch::RedemptionStatus, std::string>
|
|
||||||
redemptionStatusesTwitch = {
|
|
||||||
{MacroActionTwitch::RedemptionStatus::CANCELED, "CANCELED"},
|
|
||||||
{MacroActionTwitch::RedemptionStatus::FULFILLED, "FULFILLED"},
|
|
||||||
};
|
|
||||||
|
|
||||||
void MacroActionTwitch::SetStreamTitle(
|
void MacroActionTwitch::SetStreamTitle(
|
||||||
const std::shared_ptr<TwitchToken> &token) const
|
const std::shared_ptr<TwitchToken> &token) const
|
||||||
{
|
{
|
||||||
@@ -79,10 +73,11 @@ void MacroActionTwitch::SetStreamTitle(
|
|||||||
|
|
||||||
OBSDataAutoRelease data = obs_data_create();
|
OBSDataAutoRelease data = obs_data_create();
|
||||||
obs_data_set_string(data, "title", _streamTitle.c_str());
|
obs_data_set_string(data, "title", _streamTitle.c_str());
|
||||||
auto result = SendPatchRequest(*token, "https://api.twitch.tv",
|
auto result = SendPatchRequest(
|
||||||
"/helix/channels",
|
"https://api.twitch.tv",
|
||||||
{{"broadcaster_id", token->GetUserID()}},
|
std::string("/helix/channels?broadcaster_id=") +
|
||||||
data.Get());
|
token->GetUserID(),
|
||||||
|
*token, data.Get());
|
||||||
|
|
||||||
if (result.status != 204) {
|
if (result.status != 204) {
|
||||||
blog(LOG_INFO, "Failed to set stream title! (%d)",
|
blog(LOG_INFO, "Failed to set stream title! (%d)",
|
||||||
@@ -100,11 +95,11 @@ void MacroActionTwitch::SetStreamCategory(
|
|||||||
OBSDataAutoRelease data = obs_data_create();
|
OBSDataAutoRelease data = obs_data_create();
|
||||||
obs_data_set_string(data, "game_id",
|
obs_data_set_string(data, "game_id",
|
||||||
std::to_string(_category.id).c_str());
|
std::to_string(_category.id).c_str());
|
||||||
auto result = SendPatchRequest(*token, "https://api.twitch.tv",
|
auto result = SendPatchRequest(
|
||||||
"/helix/channels",
|
"https://api.twitch.tv",
|
||||||
{{"broadcaster_id", token->GetUserID()}},
|
std::string("/helix/channels?broadcaster_id=") +
|
||||||
data.Get());
|
token->GetUserID(),
|
||||||
|
*token, data.Get());
|
||||||
if (result.status != 204) {
|
if (result.status != 204) {
|
||||||
blog(LOG_INFO, "Failed to set stream category! (%d)",
|
blog(LOG_INFO, "Failed to set stream category! (%d)",
|
||||||
result.status);
|
result.status);
|
||||||
@@ -122,8 +117,9 @@ void MacroActionTwitch::CreateStreamMarker(
|
|||||||
_markerDescription.c_str());
|
_markerDescription.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto result = SendPostRequest(*token, "https://api.twitch.tv",
|
auto result = SendPostRequest("https://api.twitch.tv",
|
||||||
"/helix/streams/markers", {}, data.Get());
|
"/helix/streams/markers", *token,
|
||||||
|
data.Get());
|
||||||
|
|
||||||
if (result.status != 200) {
|
if (result.status != 200) {
|
||||||
blog(LOG_INFO, "Failed to create marker! (%d)", result.status);
|
blog(LOG_INFO, "Failed to create marker! (%d)", result.status);
|
||||||
@@ -133,12 +129,14 @@ void MacroActionTwitch::CreateStreamMarker(
|
|||||||
void MacroActionTwitch::CreateStreamClip(
|
void MacroActionTwitch::CreateStreamClip(
|
||||||
const std::shared_ptr<TwitchToken> &token) const
|
const std::shared_ptr<TwitchToken> &token) const
|
||||||
{
|
{
|
||||||
|
OBSDataAutoRelease data = obs_data_create();
|
||||||
auto hasDelay = _clipHasDelay ? "true" : "false";
|
auto hasDelay = _clipHasDelay ? "true" : "false";
|
||||||
|
|
||||||
auto result = SendPostRequest(*token, "https://api.twitch.tv",
|
auto result = SendPostRequest(
|
||||||
"/helix/clips",
|
"https://api.twitch.tv",
|
||||||
{{"broadcaster_id", token->GetUserID()},
|
"/helix/clips?broadcaster_id=" + token->GetUserID() +
|
||||||
{"has_delay", hasDelay}});
|
"&has_delay=" + hasDelay,
|
||||||
|
*token, data.Get());
|
||||||
|
|
||||||
if (result.status != 202) {
|
if (result.status != 202) {
|
||||||
blog(LOG_INFO, "Failed to create clip! (%d)", result.status);
|
blog(LOG_INFO, "Failed to create clip! (%d)", result.status);
|
||||||
@@ -151,10 +149,9 @@ void MacroActionTwitch::StartCommercial(
|
|||||||
OBSDataAutoRelease data = obs_data_create();
|
OBSDataAutoRelease data = obs_data_create();
|
||||||
obs_data_set_string(data, "broadcaster_id", token->GetUserID().c_str());
|
obs_data_set_string(data, "broadcaster_id", token->GetUserID().c_str());
|
||||||
obs_data_set_int(data, "length", _duration.Seconds());
|
obs_data_set_int(data, "length", _duration.Seconds());
|
||||||
auto result = SendPostRequest(*token, "https://api.twitch.tv",
|
auto result = SendPostRequest("https://api.twitch.tv",
|
||||||
"/helix/channels/commercial", {},
|
"/helix/channels/commercial", *token,
|
||||||
data.Get());
|
data.Get());
|
||||||
|
|
||||||
if (result.status != 200) {
|
if (result.status != 200) {
|
||||||
OBSDataArrayAutoRelease replyArray =
|
OBSDataArrayAutoRelease replyArray =
|
||||||
obs_data_get_array(result.data, "data");
|
obs_data_get_array(result.data, "data");
|
||||||
@@ -181,10 +178,11 @@ void MacroActionTwitch::SendChatAnnouncement(
|
|||||||
announcementColorsTwitch.at(_announcementColor).c_str());
|
announcementColorsTwitch.at(_announcementColor).c_str());
|
||||||
auto userId = token->GetUserID();
|
auto userId = token->GetUserID();
|
||||||
|
|
||||||
auto result = SendPostRequest(
|
auto result =
|
||||||
*token, "https://api.twitch.tv", "/helix/chat/announcements",
|
SendPostRequest("https://api.twitch.tv",
|
||||||
{{"broadcaster_id", userId}, {"moderator_id", userId}},
|
"/helix/chat/announcements?broadcaster_id=" +
|
||||||
data.Get());
|
userId + "&moderator_id=" + userId,
|
||||||
|
*token, data.Get());
|
||||||
|
|
||||||
if (result.status != 204) {
|
if (result.status != 204) {
|
||||||
blog(LOG_INFO, "Failed to send chat announcement! (%d)",
|
blog(LOG_INFO, "Failed to send chat announcement! (%d)",
|
||||||
@@ -199,10 +197,11 @@ void MacroActionTwitch::SetChatEmoteOnlyMode(
|
|||||||
obs_data_set_bool(data, "emote_mode", enable);
|
obs_data_set_bool(data, "emote_mode", enable);
|
||||||
auto userId = token->GetUserID();
|
auto userId = token->GetUserID();
|
||||||
|
|
||||||
auto result = SendPatchRequest(
|
auto result =
|
||||||
*token, "https://api.twitch.tv", "/helix/chat/settings",
|
SendPatchRequest("https://api.twitch.tv",
|
||||||
{{"broadcaster_id", userId}, {"moderator_id", userId}},
|
"/helix/chat/settings?broadcaster_id=" +
|
||||||
data.Get());
|
userId + "&moderator_id=" + userId,
|
||||||
|
*token, data.Get());
|
||||||
|
|
||||||
if (result.status != 200) {
|
if (result.status != 200) {
|
||||||
blog(LOG_INFO, "Failed to %s chat's emote-only mode! (%d)",
|
blog(LOG_INFO, "Failed to %s chat's emote-only mode! (%d)",
|
||||||
@@ -217,9 +216,8 @@ void MacroActionTwitch::StartRaid(const std::shared_ptr<TwitchToken> &token)
|
|||||||
token->GetUserID().c_str());
|
token->GetUserID().c_str());
|
||||||
obs_data_set_string(data, "to_broadcaster_id",
|
obs_data_set_string(data, "to_broadcaster_id",
|
||||||
_channel.GetUserID(*token).c_str());
|
_channel.GetUserID(*token).c_str());
|
||||||
auto result = SendPostRequest(*token, "https://api.twitch.tv",
|
auto result = SendPostRequest("https://api.twitch.tv", "/helix/raids",
|
||||||
"/helix/raids", {}, data.Get());
|
*token, data.Get());
|
||||||
|
|
||||||
if (result.status != 200) {
|
if (result.status != 200) {
|
||||||
blog(LOG_INFO, "Failed to start raid! (%d)\n", result.status);
|
blog(LOG_INFO, "Failed to start raid! (%d)\n", result.status);
|
||||||
}
|
}
|
||||||
@@ -245,32 +243,33 @@ bool MacroActionTwitch::PerformAction()
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (_action) {
|
switch (_action) {
|
||||||
case Action::CHANNEL_INFO_TITLE_SET:
|
case MacroActionTwitch::Action::TITLE:
|
||||||
SetStreamTitle(token);
|
SetStreamTitle(token);
|
||||||
break;
|
break;
|
||||||
case Action::CHANNEL_INFO_CATEGORY_SET:
|
case MacroActionTwitch::Action::CATEGORY:
|
||||||
SetStreamCategory(token);
|
SetStreamCategory(token);
|
||||||
break;
|
break;
|
||||||
case Action::RAID_START:
|
case MacroActionTwitch::Action::MARKER:
|
||||||
StartRaid(token);
|
|
||||||
break;
|
|
||||||
case Action::COMMERCIAL_START:
|
|
||||||
StartCommercial(token);
|
|
||||||
break;
|
|
||||||
case Action::MARKER_CREATE:
|
|
||||||
CreateStreamMarker(token);
|
CreateStreamMarker(token);
|
||||||
break;
|
break;
|
||||||
case Action::CLIP_CREATE:
|
case MacroActionTwitch::Action::CLIP:
|
||||||
CreateStreamClip(token);
|
CreateStreamClip(token);
|
||||||
break;
|
break;
|
||||||
case Action::CHAT_ANNOUNCEMENT_SEND:
|
case MacroActionTwitch::Action::COMMERCIAL:
|
||||||
|
StartCommercial(token);
|
||||||
|
break;
|
||||||
|
case MacroActionTwitch::Action::ANNOUNCEMENT:
|
||||||
SendChatAnnouncement(token);
|
SendChatAnnouncement(token);
|
||||||
break;
|
break;
|
||||||
case Action::CHAT_EMOTE_ONLY_ENABLE:
|
case MacroActionTwitch::Action::ENABLE_EMOTE_ONLY:
|
||||||
SetChatEmoteOnlyMode(token, true);
|
SetChatEmoteOnlyMode(token, true);
|
||||||
break;
|
break;
|
||||||
case Action::CHAT_EMOTE_ONLY_DISABLE:
|
case MacroActionTwitch::Action::DISABLE_EMOTE_ONLY:
|
||||||
SetChatEmoteOnlyMode(token, false);
|
SetChatEmoteOnlyMode(token, false);
|
||||||
|
break;
|
||||||
|
case MacroActionTwitch::Action::RAID:
|
||||||
|
StartRaid(token);
|
||||||
|
break;
|
||||||
case MacroActionTwitch::Action::SEND_CHAT_MESSAGE:
|
case MacroActionTwitch::Action::SEND_CHAT_MESSAGE:
|
||||||
SendChatMessage(token);
|
SendChatMessage(token);
|
||||||
break;
|
break;
|
||||||
@@ -339,111 +338,27 @@ bool MacroActionTwitch::Load(obs_data_t *obj)
|
|||||||
bool MacroActionTwitch::ActionIsSupportedByToken()
|
bool MacroActionTwitch::ActionIsSupportedByToken()
|
||||||
{
|
{
|
||||||
static const std::unordered_map<Action, TokenOption> requiredOption = {
|
static const std::unordered_map<Action, TokenOption> requiredOption = {
|
||||||
{Action::CHANNEL_INFO_TITLE_SET, {"channel:manage:broadcast"}},
|
{Action::TITLE, {"channel:manage:broadcast"}},
|
||||||
{Action::CHANNEL_INFO_CATEGORY_SET,
|
{Action::CATEGORY, {"channel:manage:broadcast"}},
|
||||||
{"channel:manage:broadcast"}},
|
{Action::MARKER, {"channel:manage:broadcast"}},
|
||||||
{Action::CHANNEL_INFO_LANGUAGE_SET,
|
{Action::CLIP, {"clips:edit"}},
|
||||||
{"channel:manage:broadcast"}},
|
{Action::COMMERCIAL, {"channel:edit:commercial"}},
|
||||||
{Action::CHANNEL_INFO_DELAY_SET, {"channel:manage:broadcast"}},
|
{Action::ANNOUNCEMENT, {"moderator:manage:announcements"}},
|
||||||
{Action::CHANNEL_INFO_BRANDED_CONTENT_ENABLE,
|
{Action::ENABLE_EMOTE_ONLY, {"moderator:manage:chat_settings"}},
|
||||||
{"channel:manage:broadcast"}},
|
{Action::DISABLE_EMOTE_ONLY,
|
||||||
{Action::CHANNEL_INFO_BRANDED_CONTENT_DISABLE,
|
|
||||||
{"channel:manage:broadcast"}},
|
|
||||||
{Action::RAID_START, {"channel:manage:raids"}},
|
|
||||||
{Action::RAID_END, {"channel:manage:raids"}},
|
|
||||||
{Action::SHOUTOUT_SEND, {"moderator:manage:shoutouts"}},
|
|
||||||
{Action::POLL_END, {"channel:manage:polls"}},
|
|
||||||
{Action::PREDICTION_END, {"channel:manage:predictions"}},
|
|
||||||
{Action::SHIELD_MODE_START, {"moderator:manage:shield_mode"}},
|
|
||||||
{Action::SHIELD_MODE_END, {"moderator:manage:shield_mode"}},
|
|
||||||
{Action::POINTS_REWARD_ENABLE, {"channel:manage:redemptions"}},
|
|
||||||
{Action::POINTS_REWARD_DISABLE, {"channel:manage:redemptions"}},
|
|
||||||
{Action::POINTS_REWARD_PAUSE, {"channel:manage:redemptions"}},
|
|
||||||
{Action::POINTS_REWARD_UNPAUSE, {"channel:manage:redemptions"}},
|
|
||||||
{Action::POINTS_REWARD_TITLE_SET,
|
|
||||||
{"channel:manage:redemptions"}},
|
|
||||||
{Action::POINTS_REWARD_PROMPT_SET,
|
|
||||||
{"channel:manage:redemptions"}},
|
|
||||||
{Action::POINTS_REWARD_COST_SET,
|
|
||||||
{"channel:manage:redemptions"}},
|
|
||||||
{Action::POINTS_REWARD_USER_INPUT_REQUIRE,
|
|
||||||
{"channel:manage:redemptions"}},
|
|
||||||
{Action::POINTS_REWARD_USER_INPUT_UNREQUIRE,
|
|
||||||
{"channel:manage:redemptions"}},
|
|
||||||
{Action::POINTS_REWARD_COOLDOWN_ENABLE,
|
|
||||||
{"channel:manage:redemptions"}},
|
|
||||||
{Action::POINTS_REWARD_COOLDOWN_DISABLE,
|
|
||||||
{"channel:manage:redemptions"}},
|
|
||||||
{Action::POINTS_REWARD_QUEUE_SKIP_ENABLE,
|
|
||||||
{"channel:manage:redemptions"}},
|
|
||||||
{Action::POINTS_REWARD_QUEUE_SKIP_DISABLE,
|
|
||||||
{"channel:manage:redemptions"}},
|
|
||||||
{Action::POINTS_REWARD_MAX_PER_STREAM_ENABLE,
|
|
||||||
{"channel:manage:redemptions"}},
|
|
||||||
{Action::POINTS_REWARD_MAX_PER_STREAM_DISABLE,
|
|
||||||
{"channel:manage:redemptions"}},
|
|
||||||
{Action::POINTS_REWARD_MAX_PER_USER_ENABLE,
|
|
||||||
{"channel:manage:redemptions"}},
|
|
||||||
{Action::POINTS_REWARD_MAX_PER_USER_DISABLE,
|
|
||||||
{"channel:manage:redemptions"}},
|
|
||||||
{Action::POINTS_REWARD_DELETE, {"channel:manage:redemptions"}},
|
|
||||||
{Action::POINTS_REWARD_REDEMPTION_CANCEL,
|
|
||||||
{"channel:manage:redemptions"}},
|
|
||||||
{Action::POINTS_REWARD_REDEMPTION_FULFILL,
|
|
||||||
{"channel:manage:redemptions"}},
|
|
||||||
{Action::USER_BAN, {"moderator:manage:banned_users"}},
|
|
||||||
{Action::USER_UNBAN, {"moderator:manage:banned_users"}},
|
|
||||||
{Action::USER_BLOCK, {"user:manage:blocked_users"}},
|
|
||||||
{Action::USER_UNBLOCK, {"user:manage:blocked_users"}},
|
|
||||||
{Action::USER_MODERATOR_ADD, {"channel:manage:moderators"}},
|
|
||||||
{Action::USER_MODERATOR_DELETE, {"channel:manage:moderators"}},
|
|
||||||
{Action::USER_VIP_ADD, {"channel:manage:vips"}},
|
|
||||||
{Action::USER_VIP_DELETE, {"channel:manage:vips"}},
|
|
||||||
{Action::COMMERCIAL_START, {"channel:edit:commercial"}},
|
|
||||||
{Action::COMMERCIAL_SNOOZE, {"channel:manage:ads"}},
|
|
||||||
{Action::MARKER_CREATE, {"channel:manage:broadcast"}},
|
|
||||||
{Action::CLIP_CREATE, {"clips:edit"}},
|
|
||||||
{Action::CHAT_ANNOUNCEMENT_SEND,
|
|
||||||
{"moderator:manage:announcements"}},
|
|
||||||
{Action::CHAT_EMOTE_ONLY_ENABLE,
|
|
||||||
{"moderator:manage:chat_settings"}},
|
{"moderator:manage:chat_settings"}},
|
||||||
{Action::CHAT_EMOTE_ONLY_DISABLE,
|
{Action::RAID, {"channel:manage:raids"}},
|
||||||
{"moderator:manage:chat_settings"}},
|
|
||||||
{Action::CHAT_FOLLOWER_ONLY_ENABLE,
|
|
||||||
{"moderator:manage:chat_settings"}},
|
|
||||||
{Action::CHAT_FOLLOWER_ONLY_DISABLE,
|
|
||||||
{"moderator:manage:chat_settings"}},
|
|
||||||
{Action::CHAT_SUBSCRIBER_ONLY_ENABLE,
|
|
||||||
{"moderator:manage:chat_settings"}},
|
|
||||||
{Action::CHAT_SUBSCRIBER_ONLY_DISABLE,
|
|
||||||
{"moderator:manage:chat_settings"}},
|
|
||||||
{Action::CHAT_SLOW_MODE_ENABLE,
|
|
||||||
{"moderator:manage:chat_settings"}},
|
|
||||||
{Action::CHAT_SLOW_MODE_DISABLE,
|
|
||||||
{"moderator:manage:chat_settings"}},
|
|
||||||
{Action::CHAT_NON_MODERATOR_DELAY_ENABLE,
|
|
||||||
{"moderator:manage:chat_settings"}},
|
|
||||||
{Action::CHAT_NON_MODERATOR_DELAY_DISABLE,
|
|
||||||
{"moderator:manage:chat_settings"}},
|
|
||||||
{Action::CHAT_UNIQUE_MODE_ENABLE,
|
|
||||||
{"moderator:manage:chat_settings"}},
|
|
||||||
{Action::CHAT_UNIQUE_MODE_DISABLE,
|
|
||||||
{"moderator:manage:chat_settings"}},
|
|
||||||
{Action::WHISPER_SEND, {"user:manage:whispers"}},
|
|
||||||
{Action::SEND_CHAT_MESSAGE, {"chat:edit"}},
|
{Action::SEND_CHAT_MESSAGE, {"chat:edit"}},
|
||||||
};
|
};
|
||||||
|
|
||||||
auto token = _token.lock();
|
auto token = _token.lock();
|
||||||
if (!token) {
|
if (!token) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto option = requiredOption.find(_action);
|
auto option = requiredOption.find(_action);
|
||||||
assert(option != requiredOption.end());
|
assert(option != requiredOption.end());
|
||||||
if (option == requiredOption.end()) {
|
if (option == requiredOption.end()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return token->OptionIsEnabled(option->second);
|
return token->OptionIsEnabled(option->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -486,8 +401,49 @@ MacroActionTwitchEdit::MacroActionTwitchEdit(
|
|||||||
_channel(new TwitchChannelSelection(this)),
|
_channel(new TwitchChannelSelection(this)),
|
||||||
_chatMessage(new VariableTextEdit(this))
|
_chatMessage(new VariableTextEdit(this))
|
||||||
{
|
{
|
||||||
SetWidgetProperties();
|
_streamTitle->setSizePolicy(QSizePolicy::MinimumExpanding,
|
||||||
SetWidgetSignalConnections();
|
QSizePolicy::Preferred);
|
||||||
|
_streamTitle->setMaxLength(140);
|
||||||
|
_markerDescription->setSizePolicy(QSizePolicy::MinimumExpanding,
|
||||||
|
QSizePolicy::Preferred);
|
||||||
|
_markerDescription->setMaxLength(140);
|
||||||
|
_announcementMessage->setSizePolicy(QSizePolicy::MinimumExpanding,
|
||||||
|
QSizePolicy::Preferred);
|
||||||
|
_announcementMessage->setMaxLength(500);
|
||||||
|
|
||||||
|
auto spinBox = _duration->SpinBox();
|
||||||
|
spinBox->setSuffix("s");
|
||||||
|
spinBox->setMaximum(180);
|
||||||
|
|
||||||
|
populateActionSelection(_actions);
|
||||||
|
populateAnnouncementColorSelection(_announcementColor);
|
||||||
|
|
||||||
|
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
|
||||||
|
SLOT(ActionChanged(int)));
|
||||||
|
QWidget::connect(_tokens, SIGNAL(SelectionChanged(const QString &)),
|
||||||
|
this, SLOT(TwitchTokenChanged(const QString &)));
|
||||||
|
QWidget::connect(&_tokenPermissionCheckTimer, SIGNAL(timeout()), this,
|
||||||
|
SLOT(CheckTokenPermissions()));
|
||||||
|
QWidget::connect(_streamTitle, SIGNAL(editingFinished()), this,
|
||||||
|
SLOT(StreamTitleChanged()));
|
||||||
|
QWidget::connect(_category,
|
||||||
|
SIGNAL(CategoreyChanged(const TwitchCategory &)), this,
|
||||||
|
SLOT(CategoreyChanged(const TwitchCategory &)));
|
||||||
|
QWidget::connect(_markerDescription, SIGNAL(editingFinished()), this,
|
||||||
|
SLOT(MarkerDescriptionChanged()));
|
||||||
|
QObject::connect(_clipHasDelay, SIGNAL(stateChanged(int)), this,
|
||||||
|
SLOT(ClipHasDelayChanged(int)));
|
||||||
|
QObject::connect(_duration, SIGNAL(DurationChanged(const Duration &)),
|
||||||
|
this, SLOT(DurationChanged(const Duration &)));
|
||||||
|
QWidget::connect(_announcementMessage, SIGNAL(textChanged()), this,
|
||||||
|
SLOT(AnnouncementMessageChanged()));
|
||||||
|
QWidget::connect(_announcementColor, SIGNAL(currentIndexChanged(int)),
|
||||||
|
this, SLOT(AnnouncementColorChanged(int)));
|
||||||
|
QWidget::connect(_channel,
|
||||||
|
SIGNAL(ChannelChanged(const TwitchChannel &)), this,
|
||||||
|
SLOT(ChannelChanged(const TwitchChannel &)));
|
||||||
|
QWidget::connect(_chatMessage, SIGNAL(textChanged()), this,
|
||||||
|
SLOT(ChatMessageChanged()));
|
||||||
|
|
||||||
_entryData = entryData;
|
_entryData = entryData;
|
||||||
SetWidgetLayout();
|
SetWidgetLayout();
|
||||||
@@ -521,8 +477,8 @@ void MacroActionTwitchEdit::ActionChanged(int idx)
|
|||||||
auto lock = LockContext();
|
auto lock = LockContext();
|
||||||
_entryData->_action = static_cast<MacroActionTwitch::Action>(
|
_entryData->_action = static_cast<MacroActionTwitch::Action>(
|
||||||
_actions->itemData(idx).toInt());
|
_actions->itemData(idx).toInt());
|
||||||
|
SetupWidgetVisibility();
|
||||||
SetWidgetLayout();
|
SetWidgetLayout();
|
||||||
SetWidgetVisibility();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroActionTwitchEdit::TwitchTokenChanged(const QString &token)
|
void MacroActionTwitchEdit::TwitchTokenChanged(const QString &token)
|
||||||
@@ -536,7 +492,7 @@ void MacroActionTwitchEdit::TwitchTokenChanged(const QString &token)
|
|||||||
_category->SetToken(_entryData->_token);
|
_category->SetToken(_entryData->_token);
|
||||||
_channel->SetToken(_entryData->_token);
|
_channel->SetToken(_entryData->_token);
|
||||||
|
|
||||||
SetWidgetVisibility();
|
SetupWidgetVisibility();
|
||||||
emit(HeaderInfoChanged(token));
|
emit(HeaderInfoChanged(token));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -624,86 +580,30 @@ void MacroActionTwitchEdit::AnnouncementColorChanged(int index)
|
|||||||
static_cast<MacroActionTwitch::AnnouncementColor>(index);
|
static_cast<MacroActionTwitch::AnnouncementColor>(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroActionTwitchEdit::SetWidgetProperties()
|
void MacroActionTwitchEdit::SetupWidgetVisibility()
|
||||||
{
|
{
|
||||||
_streamTitle->setSizePolicy(QSizePolicy::MinimumExpanding,
|
_streamTitle->setVisible(_entryData->_action ==
|
||||||
QSizePolicy::Preferred);
|
MacroActionTwitch::Action::TITLE);
|
||||||
_streamTitle->setMaxLength(140);
|
_category->setVisible(_entryData->_action ==
|
||||||
_markerDescription->setSizePolicy(QSizePolicy::MinimumExpanding,
|
MacroActionTwitch::Action::CATEGORY);
|
||||||
QSizePolicy::Preferred);
|
_markerDescription->setVisible(_entryData->_action ==
|
||||||
_markerDescription->setMaxLength(140);
|
MacroActionTwitch::Action::MARKER);
|
||||||
_announcementMessage->setMaxLength(500);
|
_clipHasDelay->setVisible(_entryData->_action ==
|
||||||
|
MacroActionTwitch::Action::CLIP);
|
||||||
auto durationSpinBox = _duration->SpinBox();
|
_duration->setVisible(_entryData->_action ==
|
||||||
durationSpinBox->setMaximum(180);
|
MacroActionTwitch::Action::COMMERCIAL);
|
||||||
durationSpinBox->setSuffix("s");
|
_announcementMessage->setVisible(
|
||||||
|
_entryData->_action == MacroActionTwitch::Action::ANNOUNCEMENT);
|
||||||
populateActionSelection(_actions);
|
_announcementColor->setVisible(_entryData->_action ==
|
||||||
populateAnnouncementColorSelection(_announcementColor);
|
MacroActionTwitch::Action::ANNOUNCEMENT);
|
||||||
}
|
|
||||||
|
|
||||||
void MacroActionTwitchEdit::SetWidgetSignalConnections()
|
|
||||||
{
|
|
||||||
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
|
|
||||||
SLOT(ActionChanged(int)));
|
|
||||||
QWidget::connect(_tokens, SIGNAL(SelectionChanged(const QString &)),
|
|
||||||
this, SLOT(TwitchTokenChanged(const QString &)));
|
|
||||||
QWidget::connect(&_tokenPermissionCheckTimer, SIGNAL(timeout()), this,
|
|
||||||
SLOT(CheckTokenPermissions()));
|
|
||||||
QWidget::connect(_streamTitle, SIGNAL(editingFinished()), this,
|
|
||||||
SLOT(StreamTitleChanged()));
|
|
||||||
QWidget::connect(_category,
|
|
||||||
SIGNAL(CategoreyChanged(const TwitchCategory &)), this,
|
|
||||||
SLOT(CategoreyChanged(const TwitchCategory &)));
|
|
||||||
QWidget::connect(_markerDescription, SIGNAL(editingFinished()), this,
|
|
||||||
SLOT(MarkerDescriptionChanged()));
|
|
||||||
QObject::connect(_clipHasDelay, SIGNAL(stateChanged(int)), this,
|
|
||||||
SLOT(ClipHasDelayChanged(int)));
|
|
||||||
QObject::connect(_duration, SIGNAL(DurationChanged(const Duration &)),
|
|
||||||
this, SLOT(DurationChanged(const Duration &)));
|
|
||||||
QWidget::connect(_announcementMessage, SIGNAL(textChanged()), this,
|
|
||||||
SLOT(AnnouncementMessageChanged()));
|
|
||||||
QWidget::connect(_announcementColor, SIGNAL(currentIndexChanged(int)),
|
|
||||||
this, SLOT(AnnouncementColorChanged(int)));
|
|
||||||
QWidget::connect(_channel,
|
|
||||||
SIGNAL(ChannelChanged(const TwitchChannel &)), this,
|
|
||||||
SLOT(ChannelChanged(const TwitchChannel &)));
|
|
||||||
QWidget::connect(_chatMessage, SIGNAL(textChanged()), this,
|
|
||||||
SLOT(ChatMessageChanged()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroActionTwitchEdit::SetWidgetVisibility()
|
|
||||||
{
|
|
||||||
_streamTitle->setVisible(
|
|
||||||
_entryData->_action ==
|
|
||||||
MacroActionTwitch::Action::CHANNEL_INFO_TITLE_SET);
|
|
||||||
_category->setVisible(
|
|
||||||
_entryData->_action ==
|
|
||||||
MacroActionTwitch::Action::CHANNEL_INFO_CATEGORY_SET);
|
|
||||||
_channel->setVisible(
|
_channel->setVisible(
|
||||||
_entryData->_action == MacroActionTwitch::Action::RAID_START ||
|
_entryData->_action == MacroActionTwitch::Action::RAID ||
|
||||||
_entryData->_action == MacroActionTwitch::Action::RAID_END ||
|
|
||||||
_entryData->_action ==
|
_entryData->_action ==
|
||||||
MacroActionTwitch::Action::SEND_CHAT_MESSAGE);
|
MacroActionTwitch::Action::SEND_CHAT_MESSAGE);
|
||||||
_duration->setVisible(_entryData->_action ==
|
|
||||||
MacroActionTwitch::Action::COMMERCIAL_START);
|
|
||||||
_markerDescription->setVisible(
|
|
||||||
_entryData->_action ==
|
|
||||||
MacroActionTwitch::Action::MARKER_CREATE);
|
|
||||||
_clipHasDelay->setVisible(_entryData->_action ==
|
|
||||||
MacroActionTwitch::Action::CLIP_CREATE);
|
|
||||||
_announcementMessage->setVisible(
|
|
||||||
_entryData->_action ==
|
|
||||||
MacroActionTwitch::Action::CHAT_ANNOUNCEMENT_SEND);
|
|
||||||
_announcementColor->setVisible(
|
|
||||||
_entryData->_action ==
|
|
||||||
MacroActionTwitch::Action::CHAT_ANNOUNCEMENT_SEND);
|
|
||||||
_chatMessage->setVisible(_entryData->_action ==
|
_chatMessage->setVisible(_entryData->_action ==
|
||||||
MacroActionTwitch::Action::SEND_CHAT_MESSAGE);
|
MacroActionTwitch::Action::SEND_CHAT_MESSAGE);
|
||||||
|
if (_entryData->_action == MacroActionTwitch::Action::TITLE ||
|
||||||
if (_entryData->_action ==
|
_entryData->_action == MacroActionTwitch::Action::MARKER) {
|
||||||
MacroActionTwitch::Action::CHANNEL_INFO_TITLE_SET ||
|
|
||||||
_entryData->_action == MacroActionTwitch::Action::MARKER_CREATE) {
|
|
||||||
RemoveStretchIfPresent(_layout);
|
RemoveStretchIfPresent(_layout);
|
||||||
} else {
|
} else {
|
||||||
AddStretchIfNecessary(_layout);
|
AddStretchIfNecessary(_layout);
|
||||||
@@ -741,7 +641,7 @@ void MacroActionTwitchEdit::ChatMessageChanged()
|
|||||||
|
|
||||||
void MacroActionTwitchEdit::SetWidgetLayout()
|
void MacroActionTwitchEdit::SetWidgetLayout()
|
||||||
{
|
{
|
||||||
const std::vector<QWidget *> widgets{
|
static const std::vector<QWidget *> widgets{
|
||||||
_tokens, _actions, _streamTitle,
|
_tokens, _actions, _streamTitle,
|
||||||
_category, _markerDescription, _clipHasDelay,
|
_category, _markerDescription, _clipHasDelay,
|
||||||
_duration, _announcementColor, _channel};
|
_duration, _announcementColor, _channel};
|
||||||
@@ -792,7 +692,7 @@ void MacroActionTwitchEdit::UpdateEntryData()
|
|||||||
_channel->SetChannel(_entryData->_channel);
|
_channel->SetChannel(_entryData->_channel);
|
||||||
_chatMessage->setPlainText(_entryData->_chatMessage);
|
_chatMessage->setPlainText(_entryData->_chatMessage);
|
||||||
|
|
||||||
SetWidgetVisibility();
|
SetupWidgetVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
#include "category-selection.hpp"
|
#include "category-selection.hpp"
|
||||||
#include "channel-selection.hpp"
|
#include "channel-selection.hpp"
|
||||||
#include "chat-connection.hpp"
|
#include "chat-connection.hpp"
|
||||||
#include "points-reward-selection.hpp"
|
|
||||||
|
|
||||||
#include <variable-line-edit.hpp>
|
#include <variable-line-edit.hpp>
|
||||||
#include <variable-text-edit.hpp>
|
#include <variable-text-edit.hpp>
|
||||||
@@ -23,118 +22,16 @@ public:
|
|||||||
std::string GetShortDesc() const;
|
std::string GetShortDesc() const;
|
||||||
|
|
||||||
enum class Action {
|
enum class Action {
|
||||||
// Channel info update
|
TITLE,
|
||||||
CHANNEL_INFO_TITLE_SET = 10,
|
CATEGORY = 10,
|
||||||
CHANNEL_INFO_CATEGORY_SET = 20,
|
MARKER = 20,
|
||||||
CHANNEL_INFO_LANGUAGE_SET = 30,
|
CLIP = 30,
|
||||||
CHANNEL_INFO_DELAY_SET = 40,
|
COMMERCIAL = 40,
|
||||||
CHANNEL_INFO_TAGS_SET = 50, // TODO
|
ANNOUNCEMENT = 50,
|
||||||
CHANNEL_INFO_CONTENT_LABELS_SET = 60, // TODO
|
ENABLE_EMOTE_ONLY = 60,
|
||||||
CHANNEL_INFO_BRANDED_CONTENT_ENABLE = 70,
|
DISABLE_EMOTE_ONLY = 70,
|
||||||
CHANNEL_INFO_BRANDED_CONTENT_DISABLE = 71,
|
RAID = 80,
|
||||||
|
SEND_CHAT_MESSAGE = 90,
|
||||||
// Raid
|
|
||||||
RAID_START = 110,
|
|
||||||
RAID_END = 120,
|
|
||||||
|
|
||||||
// Shoutout
|
|
||||||
SHOUTOUT_SEND = 200,
|
|
||||||
|
|
||||||
// Poll
|
|
||||||
POLL_START = 300, // TODO
|
|
||||||
POLL_END = 310,
|
|
||||||
|
|
||||||
// Prediction
|
|
||||||
PREDICTION_START = 400, // TODO
|
|
||||||
PREDICTION_END = 410,
|
|
||||||
|
|
||||||
// Shield mode
|
|
||||||
SHIELD_MODE_START = 500,
|
|
||||||
SHIELD_MODE_END = 501,
|
|
||||||
|
|
||||||
// Reward add
|
|
||||||
POINTS_REWARD_ADD = 600, // TODO
|
|
||||||
|
|
||||||
// Reward update
|
|
||||||
POINTS_REWARD_ENABLE = 710,
|
|
||||||
POINTS_REWARD_DISABLE = 711,
|
|
||||||
POINTS_REWARD_PAUSE = 712,
|
|
||||||
POINTS_REWARD_UNPAUSE = 713,
|
|
||||||
POINTS_REWARD_TITLE_SET = 720,
|
|
||||||
POINTS_REWARD_PROMPT_SET = 730,
|
|
||||||
POINTS_REWARD_COST_SET = 740,
|
|
||||||
POINTS_REWARD_BACKGROUND_COLOR_SET = 750, // TODO
|
|
||||||
POINTS_REWARD_USER_INPUT_REQUIRE = 760,
|
|
||||||
POINTS_REWARD_USER_INPUT_UNREQUIRE = 761,
|
|
||||||
POINTS_REWARD_COOLDOWN_ENABLE = 770,
|
|
||||||
POINTS_REWARD_COOLDOWN_DISABLE = 771,
|
|
||||||
POINTS_REWARD_QUEUE_SKIP_ENABLE = 780,
|
|
||||||
POINTS_REWARD_QUEUE_SKIP_DISABLE = 781,
|
|
||||||
POINTS_REWARD_MAX_PER_STREAM_ENABLE = 790,
|
|
||||||
POINTS_REWARD_MAX_PER_STREAM_DISABLE = 791,
|
|
||||||
POINTS_REWARD_MAX_PER_USER_ENABLE = 792,
|
|
||||||
POINTS_REWARD_MAX_PER_USER_DISABLE = 793,
|
|
||||||
|
|
||||||
// Reward delete
|
|
||||||
POINTS_REWARD_DELETE = 800,
|
|
||||||
|
|
||||||
// Reward redemption update
|
|
||||||
POINTS_REWARD_REDEMPTION_FULFILL = 900,
|
|
||||||
POINTS_REWARD_REDEMPTION_CANCEL = 910,
|
|
||||||
|
|
||||||
// User state
|
|
||||||
USER_BAN = 1000,
|
|
||||||
USER_UNBAN = 1100,
|
|
||||||
USER_BLOCK = 1200,
|
|
||||||
USER_UNBLOCK = 1300,
|
|
||||||
USER_MODERATOR_ADD = 1400,
|
|
||||||
USER_MODERATOR_DELETE = 1500,
|
|
||||||
USER_VIP_ADD = 1600,
|
|
||||||
USER_VIP_DELETE = 1700,
|
|
||||||
USER_CHAT_COLOR_UPDATE = 1800, // TODO
|
|
||||||
|
|
||||||
// Commercial
|
|
||||||
COMMERCIAL_START = 1900,
|
|
||||||
COMMERCIAL_SNOOZE = 2000,
|
|
||||||
|
|
||||||
// Marker
|
|
||||||
MARKER_CREATE = 2100,
|
|
||||||
|
|
||||||
// Clips
|
|
||||||
CLIP_CREATE = 2200,
|
|
||||||
|
|
||||||
// Videos
|
|
||||||
VIDEOS_DELETE = 2300, // TODO
|
|
||||||
|
|
||||||
// Chat
|
|
||||||
CHAT_MESSAGES_DELETE = 2400, // TODO
|
|
||||||
CHAT_ANNOUNCEMENT_SEND = 2500,
|
|
||||||
CHAT_EMOTE_ONLY_ENABLE = 2600,
|
|
||||||
CHAT_EMOTE_ONLY_DISABLE = 2601,
|
|
||||||
CHAT_FOLLOWER_ONLY_ENABLE = 2602,
|
|
||||||
CHAT_FOLLOWER_ONLY_DISABLE = 2603,
|
|
||||||
CHAT_SUBSCRIBER_ONLY_ENABLE = 2604,
|
|
||||||
CHAT_SUBSCRIBER_ONLY_DISABLE = 2605,
|
|
||||||
CHAT_SLOW_MODE_ENABLE = 2640,
|
|
||||||
CHAT_SLOW_MODE_DISABLE = 2641,
|
|
||||||
CHAT_NON_MODERATOR_DELAY_ENABLE = 2650,
|
|
||||||
CHAT_NON_MODERATOR_DELAY_DISABLE = 2651,
|
|
||||||
CHAT_UNIQUE_MODE_ENABLE = 2960,
|
|
||||||
CHAT_UNIQUE_MODE_DISABLE = 2661,
|
|
||||||
CHAT_AUTOMOD_UPDATE = 2700, // TODO
|
|
||||||
CHAT_AUTOMOD_MESSAGE_ALLOW = 2800, // TODO
|
|
||||||
CHAT_AUTOMOD_MESSAGE_DENY = 2801, // TODO
|
|
||||||
CHAT_BLOCKED_TERM_ADD = 2900, // TODO
|
|
||||||
CHAT_BLOCKED_TERM_DELETE = 3000, // TODO
|
|
||||||
WHISPER_SEND = 3100,
|
|
||||||
|
|
||||||
// Schedule
|
|
||||||
CHANNEL_SCHEDULE_UPDATE = 3200, // TODO
|
|
||||||
CHANNEL_SCHEDULE_SEGMENT_ADD = 3300, // TODO
|
|
||||||
CHANNEL_SCHEDULE_SEGMENT_UPDATE = 3400, // TODO
|
|
||||||
CHANNEL_SCHEDULE_SEGMENT_DELETE = 3500, // TODO
|
|
||||||
|
|
||||||
SEND_CHAT_MESSAGE = 5000,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class AnnouncementColor {
|
enum class AnnouncementColor {
|
||||||
@@ -145,8 +42,6 @@ public:
|
|||||||
PURPLE,
|
PURPLE,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class RedemptionStatus { CANCELED, FULFILLED };
|
|
||||||
|
|
||||||
bool PerformAction();
|
bool PerformAction();
|
||||||
void LogAction() const;
|
void LogAction() const;
|
||||||
bool Save(obs_data_t *obj) const;
|
bool Save(obs_data_t *obj) const;
|
||||||
@@ -154,7 +49,7 @@ public:
|
|||||||
bool ActionIsSupportedByToken();
|
bool ActionIsSupportedByToken();
|
||||||
void ResetChatConnection();
|
void ResetChatConnection();
|
||||||
|
|
||||||
Action _action = Action::CHANNEL_INFO_TITLE_SET;
|
Action _action = Action::TITLE;
|
||||||
std::weak_ptr<TwitchToken> _token;
|
std::weak_ptr<TwitchToken> _token;
|
||||||
StringVariable _streamTitle =
|
StringVariable _streamTitle =
|
||||||
obs_module_text("AdvSceneSwitcher.action.twitch.title.title");
|
obs_module_text("AdvSceneSwitcher.action.twitch.title.title");
|
||||||
@@ -224,10 +119,8 @@ protected:
|
|||||||
std::shared_ptr<MacroActionTwitch> _entryData;
|
std::shared_ptr<MacroActionTwitch> _entryData;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SetWidgetProperties();
|
void SetupWidgetVisibility();
|
||||||
void SetWidgetSignalConnections();
|
|
||||||
void SetWidgetLayout();
|
void SetWidgetLayout();
|
||||||
void SetWidgetVisibility();
|
|
||||||
|
|
||||||
QHBoxLayout *_layout;
|
QHBoxLayout *_layout;
|
||||||
FilterComboBox *_actions;
|
FilterComboBox *_actions;
|
||||||
|
|||||||
@@ -866,9 +866,7 @@ void MacroConditionTwitch::SetupTempVars()
|
|||||||
AddTempvar(id, name.empty() ? id : name, description);
|
AddTempvar(id, name.empty() ? id : name, description);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (_condition != Condition::CHAT_MESSAGE_RECEIVED &&
|
if (_condition != Condition::CHAT_MESSAGE_RECEIVED) {
|
||||||
_condition != Condition::RAID_INBOUND_EVENT &&
|
|
||||||
_condition != Condition::RAID_OUTBOUND_EVENT) {
|
|
||||||
setupTempVarHelper("broadcaster_user_id");
|
setupTempVarHelper("broadcaster_user_id");
|
||||||
setupTempVarHelper("broadcaster_user_login");
|
setupTempVarHelper("broadcaster_user_login");
|
||||||
setupTempVarHelper("broadcaster_user_name");
|
setupTempVarHelper("broadcaster_user_name");
|
||||||
@@ -1143,16 +1141,7 @@ void MacroConditionTwitch::SetupTempVars()
|
|||||||
setupTempVarHelper("user_name", ".follow");
|
setupTempVarHelper("user_name", ".follow");
|
||||||
setupTempVarHelper("followed_at");
|
setupTempVarHelper("followed_at");
|
||||||
break;
|
break;
|
||||||
case Condition::RAID_INBOUND_EVENT:
|
|
||||||
case Condition::RAID_OUTBOUND_EVENT:
|
case Condition::RAID_OUTBOUND_EVENT:
|
||||||
setupTempVarHelper("from_broadcaster_user_id", ".raid");
|
|
||||||
setupTempVarHelper("from_broadcaster_user_login", ".raid");
|
|
||||||
setupTempVarHelper("from_broadcaster_user_name", ".raid");
|
|
||||||
setupTempVarHelper("to_broadcaster_user_id", ".raid");
|
|
||||||
setupTempVarHelper("to_broadcaster_user_login", ".raid");
|
|
||||||
setupTempVarHelper("to_broadcaster_user_name", ".raid");
|
|
||||||
setupTempVarHelper("viewers", ".raid");
|
|
||||||
break;
|
|
||||||
case Condition::LIVE_POLLING:
|
case Condition::LIVE_POLLING:
|
||||||
setupTempVarHelper("id", ".stream.online");
|
setupTempVarHelper("id", ".stream.online");
|
||||||
setupTempVarHelper("game_id");
|
setupTempVarHelper("game_id");
|
||||||
@@ -1291,7 +1280,7 @@ void MacroConditionTwitchEdit::ConditionChanged(int idx)
|
|||||||
auto lock = LockContext();
|
auto lock = LockContext();
|
||||||
_entryData->SetCondition(static_cast<MacroConditionTwitch::Condition>(
|
_entryData->SetCondition(static_cast<MacroConditionTwitch::Condition>(
|
||||||
_conditions->itemData(idx).toInt()));
|
_conditions->itemData(idx).toInt()));
|
||||||
SetWidgetVisibility();
|
SetupWidgetVisibility();
|
||||||
emit TempVarsChanged();
|
emit TempVarsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1308,7 +1297,7 @@ void MacroConditionTwitchEdit::TwitchTokenChanged(const QString &token)
|
|||||||
_pointsReward->SetToken(_entryData->_token);
|
_pointsReward->SetToken(_entryData->_token);
|
||||||
_entryData->ResetChatConnection();
|
_entryData->ResetChatConnection();
|
||||||
|
|
||||||
SetWidgetVisibility();
|
SetupWidgetVisibility();
|
||||||
emit(HeaderInfoChanged(token));
|
emit(HeaderInfoChanged(token));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1399,7 +1388,7 @@ void MacroConditionTwitchEdit::CategoreyChanged(const TwitchCategory &category)
|
|||||||
_entryData->_category = category;
|
_entryData->_category = category;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionTwitchEdit::SetWidgetVisibility()
|
void MacroConditionTwitchEdit::SetupWidgetVisibility()
|
||||||
{
|
{
|
||||||
auto condition = _entryData->GetCondition();
|
auto condition = _entryData->GetCondition();
|
||||||
|
|
||||||
@@ -1459,7 +1448,7 @@ void MacroConditionTwitchEdit::UpdateEntryData()
|
|||||||
_category->SetToken(_entryData->_token);
|
_category->SetToken(_entryData->_token);
|
||||||
_category->SetCategory(_entryData->_category);
|
_category->SetCategory(_entryData->_category);
|
||||||
|
|
||||||
SetWidgetVisibility();
|
SetupWidgetVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -23,13 +23,8 @@ public:
|
|||||||
std::string GetShortDesc() const;
|
std::string GetShortDesc() const;
|
||||||
|
|
||||||
enum class Condition {
|
enum class Condition {
|
||||||
// Event based
|
// Generic event based
|
||||||
STREAM_ONLINE_EVENT = 0,
|
STREAM_ONLINE_EVENT = 0,
|
||||||
STREAM_ONLINE_LIVE_EVENT = 1,
|
|
||||||
STREAM_ONLINE_PLAYLIST_EVENT = 2,
|
|
||||||
STREAM_ONLINE_WATCHPARTY_EVENT = 3,
|
|
||||||
STREAM_ONLINE_PREMIERE_EVENT = 4,
|
|
||||||
STREAM_ONLINE_RERUN_EVENT = 5,
|
|
||||||
STREAM_OFFLINE_EVENT = 100,
|
STREAM_OFFLINE_EVENT = 100,
|
||||||
CHANNEL_INFO_UPDATE_EVENT = 200,
|
CHANNEL_INFO_UPDATE_EVENT = 200,
|
||||||
FOLLOW_EVENT = 300,
|
FOLLOW_EVENT = 300,
|
||||||
@@ -71,6 +66,13 @@ public:
|
|||||||
USER_MODERATOR_ADDITION_EVENT = 3900,
|
USER_MODERATOR_ADDITION_EVENT = 3900,
|
||||||
USER_MODERATOR_DELETION_EVENT = 4000,
|
USER_MODERATOR_DELETION_EVENT = 4000,
|
||||||
|
|
||||||
|
// Event based with custom logic
|
||||||
|
STREAM_ONLINE_LIVE_EVENT = 1,
|
||||||
|
STREAM_ONLINE_PLAYLIST_EVENT = 2,
|
||||||
|
STREAM_ONLINE_WATCHPARTY_EVENT = 3,
|
||||||
|
STREAM_ONLINE_PREMIERE_EVENT = 4,
|
||||||
|
STREAM_ONLINE_RERUN_EVENT = 5,
|
||||||
|
|
||||||
// Chat
|
// Chat
|
||||||
CHAT_MESSAGE_RECEIVED = 500000,
|
CHAT_MESSAGE_RECEIVED = 500000,
|
||||||
|
|
||||||
@@ -168,7 +170,7 @@ protected:
|
|||||||
std::shared_ptr<MacroConditionTwitch> _entryData;
|
std::shared_ptr<MacroConditionTwitch> _entryData;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SetWidgetVisibility();
|
void SetupWidgetVisibility();
|
||||||
|
|
||||||
QHBoxLayout *_layout;
|
QHBoxLayout *_layout;
|
||||||
FilterComboBox *_conditions;
|
FilterComboBox *_conditions;
|
||||||
|
|||||||
@@ -134,9 +134,9 @@ TwitchPointsRewardSelection::GetPointsRewards(
|
|||||||
httplib::Params params = {
|
httplib::Params params = {
|
||||||
{"broadcaster_id", channel.GetUserID(*token)}};
|
{"broadcaster_id", channel.GetUserID(*token)}};
|
||||||
|
|
||||||
auto response = SendGetRequest(*token, "https://api.twitch.tv",
|
auto response = SendGetRequest("https://api.twitch.tv",
|
||||||
"/helix/channel_points/custom_rewards",
|
"/helix/channel_points/custom_rewards",
|
||||||
params);
|
*token, params);
|
||||||
|
|
||||||
if (response.status != 200) {
|
if (response.status != 200) {
|
||||||
blog(LOG_WARNING,
|
blog(LOG_WARNING,
|
||||||
|
|||||||
@@ -1,24 +1,26 @@
|
|||||||
#include "token.hpp"
|
#include "token.hpp"
|
||||||
#include "twitch-helpers.hpp"
|
#include "twitch-helpers.hpp"
|
||||||
|
|
||||||
#include <plugin-state-helpers.hpp>
|
#include <switcher-data.hpp>
|
||||||
#include <log-helper.hpp>
|
|
||||||
#include <obs-module-helper.hpp>
|
|
||||||
#include <utility.hpp>
|
#include <utility.hpp>
|
||||||
#include <QScrollArea>
|
#include <QScrollArea>
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
#include <QGroupBox>
|
|
||||||
#include <QUrl>
|
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
static const int tokenGrabberPort = 8080;
|
|
||||||
|
|
||||||
static std::deque<std::shared_ptr<Item>> twitchTokens;
|
static std::deque<std::shared_ptr<Item>> twitchTokens;
|
||||||
|
|
||||||
const std::unordered_map<std::string, std::string> TokenOption::_apiIdToLocale{
|
const std::unordered_map<std::string, std::string> TokenOption::_apiIdToLocale{
|
||||||
{"channel:manage:broadcast",
|
{"channel:manage:broadcast",
|
||||||
"AdvSceneSwitcher.twitchToken.channel.broadcast.manage"},
|
"AdvSceneSwitcher.twitchToken.channel.broadcast.manage"},
|
||||||
|
{"clips:edit", "AdvSceneSwitcher.twitchToken.clips.edit"},
|
||||||
|
{"channel:edit:commercial",
|
||||||
|
"AdvSceneSwitcher.twitchToken.channel.commercial.edit"},
|
||||||
|
{"moderator:manage:announcements",
|
||||||
|
"AdvSceneSwitcher.twitchToken.moderator.announcements.manage"},
|
||||||
|
{"moderator:manage:chat_settings",
|
||||||
|
"AdvSceneSwitcher.twitchToken.moderator.chat.settings.manage"},
|
||||||
|
{"channel:manage:raids", "AdvSceneSwitcher.twitchToken.channel.raid"},
|
||||||
{"moderator:read:followers",
|
{"moderator:read:followers",
|
||||||
"AdvSceneSwitcher.twitchToken.moderator.followers.read"},
|
"AdvSceneSwitcher.twitchToken.moderator.followers.read"},
|
||||||
{"channel:read:subscriptions",
|
{"channel:read:subscriptions",
|
||||||
@@ -26,8 +28,6 @@ const std::unordered_map<std::string, std::string> TokenOption::_apiIdToLocale{
|
|||||||
{"bits:read", "AdvSceneSwitcher.twitchToken.bits.read"},
|
{"bits:read", "AdvSceneSwitcher.twitchToken.bits.read"},
|
||||||
{"moderator:read:shoutouts",
|
{"moderator:read:shoutouts",
|
||||||
"AdvSceneSwitcher.twitchToken.moderator.shoutouts.read"},
|
"AdvSceneSwitcher.twitchToken.moderator.shoutouts.read"},
|
||||||
{"channel:manage:raids",
|
|
||||||
"AdvSceneSwitcher.twitchToken.channel.raids.manage"},
|
|
||||||
{"moderator:manage:shoutouts",
|
{"moderator:manage:shoutouts",
|
||||||
"AdvSceneSwitcher.twitchToken.moderator.shoutouts.manage"},
|
"AdvSceneSwitcher.twitchToken.moderator.shoutouts.manage"},
|
||||||
{"channel:read:polls",
|
{"channel:read:polls",
|
||||||
@@ -53,26 +53,8 @@ const std::unordered_map<std::string, std::string> TokenOption::_apiIdToLocale{
|
|||||||
{"channel:manage:redemptions",
|
{"channel:manage:redemptions",
|
||||||
"AdvSceneSwitcher.twitchToken.channel.redemptions.manage"},
|
"AdvSceneSwitcher.twitchToken.channel.redemptions.manage"},
|
||||||
{"channel:moderate", "AdvSceneSwitcher.twitchToken.channel.moderate"},
|
{"channel:moderate", "AdvSceneSwitcher.twitchToken.channel.moderate"},
|
||||||
{"moderator:manage:banned_users",
|
{"moderation:read",
|
||||||
"AdvSceneSwitcher.twitchToken.moderator.bannedUsers.manage"},
|
"AdvSceneSwitcher.twitchToken.channel.moderation.read"},
|
||||||
{"user:manage:blocked_users",
|
|
||||||
"AdvSceneSwitcher.twitchToken.user.blockedUsers.manage"},
|
|
||||||
{"moderation:read", "AdvSceneSwitcher.twitchToken.moderation.read"},
|
|
||||||
{"channel:manage:moderators",
|
|
||||||
"AdvSceneSwitcher.twitchToken.channel.moderators.manage"},
|
|
||||||
{"channel:manage:vips",
|
|
||||||
"AdvSceneSwitcher.twitchToken.channel.vips.manage"},
|
|
||||||
{"channel:edit:commercial",
|
|
||||||
"AdvSceneSwitcher.twitchToken.channel.commercial.edit"},
|
|
||||||
{"channel:manage:ads",
|
|
||||||
"AdvSceneSwitcher.twitchToken.channel.ads.manage"},
|
|
||||||
{"clips:edit", "AdvSceneSwitcher.twitchToken.clips.edit"},
|
|
||||||
{"moderator:manage:announcements",
|
|
||||||
"AdvSceneSwitcher.twitchToken.moderator.announcements.manage"},
|
|
||||||
{"moderator:manage:chat_settings",
|
|
||||||
"AdvSceneSwitcher.twitchToken.moderator.chat.settings.manage"},
|
|
||||||
{"user:manage:whispers",
|
|
||||||
"AdvSceneSwitcher.twitchToken.user.whispers.manage"},
|
|
||||||
{"chat:read", "AdvSceneSwitcher.twitchToken.chat.read"},
|
{"chat:read", "AdvSceneSwitcher.twitchToken.chat.read"},
|
||||||
{"chat:edit", "AdvSceneSwitcher.twitchToken.chat.edit"},
|
{"chat:edit", "AdvSceneSwitcher.twitchToken.chat.edit"},
|
||||||
};
|
};
|
||||||
@@ -82,8 +64,8 @@ static void loadConnections(obs_data_t *obj);
|
|||||||
|
|
||||||
bool setupTwitchTokenSupport()
|
bool setupTwitchTokenSupport()
|
||||||
{
|
{
|
||||||
AddSaveStep(saveConnections);
|
GetSwitcher()->AddSaveStep(saveConnections);
|
||||||
AddLoadStep(loadConnections);
|
GetSwitcher()->AddLoadStep(loadConnections);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,7 +194,7 @@ void TwitchToken::SetToken(const std::string &value)
|
|||||||
{
|
{
|
||||||
_token = value;
|
_token = value;
|
||||||
auto res =
|
auto res =
|
||||||
SendGetRequest(*this, "https://api.twitch.tv", "/helix/users");
|
SendGetRequest("https://api.twitch.tv", "/helix/users", *this);
|
||||||
if (res.status != 200) {
|
if (res.status != 200) {
|
||||||
blog(LOG_WARNING, "failed to get Twitch user id from token!");
|
blog(LOG_WARNING, "failed to get Twitch user id from token!");
|
||||||
_userID = -1;
|
_userID = -1;
|
||||||
@@ -611,7 +593,7 @@ static std::string generateScopeString(const std::set<TokenOption> &options)
|
|||||||
|
|
||||||
static std::string getHtml(const QString &redirect)
|
static std::string getHtml(const QString &redirect)
|
||||||
{
|
{
|
||||||
QString html = R"(
|
const char *html = R"(
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Advanced scene switcher</title>
|
<title>Advanced scene switcher</title>
|
||||||
@@ -623,18 +605,17 @@ static std::string getHtml(const QString &redirect)
|
|||||||
if (document.location.hash && document.location.hash != '') {
|
if (document.location.hash && document.location.hash != '') {
|
||||||
var parsedHash = new URLSearchParams(window.location.hash.slice(1));
|
var parsedHash = new URLSearchParams(window.location.hash.slice(1));
|
||||||
if (parsedHash.get('access_token')) {
|
if (parsedHash.get('access_token')) {
|
||||||
window.location.replace(`http://localhost:%1/token?access_token=${parsedHash.get('access_token')}&state=${parsedHash.get('state')}`);
|
window.location.replace(`http://localhost:8080/token?access_token=${parsedHash.get('access_token')}&state=${parsedHash.get('state')}`);
|
||||||
output.textContent = 'It is safe to close this window';
|
output.textContent = 'It is safe to close this window';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
window.location.replace('%2');
|
window.location.replace('%1');
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>)";
|
</html>)";
|
||||||
|
|
||||||
return html.arg(QString::number(tokenGrabberPort), redirect)
|
return QString(html).arg(redirect).toStdString();
|
||||||
.toStdString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TwitchTokenSettingsDialog::RequestToken()
|
void TwitchTokenSettingsDialog::RequestToken()
|
||||||
@@ -729,16 +710,13 @@ void TokenGrabberThread::run()
|
|||||||
|
|
||||||
// Generate URI to request token
|
// Generate URI to request token
|
||||||
auto state = generateStateString();
|
auto state = generateStateString();
|
||||||
QString getTokenURI =
|
auto getTokenURI = "https://id.twitch.tv/oauth2/authorize"
|
||||||
("https://id.twitch.tv/oauth2/authorize"
|
"?response_type=token"
|
||||||
"?response_type=token"
|
"&client_id=" +
|
||||||
"&client_id=" +
|
QString(GetClientID()) +
|
||||||
QString(GetClientID()) +
|
"&redirect_uri=http://localhost:8080/auth"
|
||||||
"&redirect_uri=http://localhost:%1"
|
"&scope=" +
|
||||||
"/auth"
|
_scope + "&state=" + QString::fromStdString(state);
|
||||||
"&scope=" +
|
|
||||||
_scope + "&state=" + QString::fromStdString(state))
|
|
||||||
.arg(QString::number(tokenGrabberPort));
|
|
||||||
|
|
||||||
// Setup server receiving token string
|
// Setup server receiving token string
|
||||||
auto html = getHtml(getTokenURI);
|
auto html = getHtml(getTokenURI);
|
||||||
@@ -797,19 +775,8 @@ void TokenGrabberThread::run()
|
|||||||
|
|
||||||
// Start the server and wait
|
// Start the server and wait
|
||||||
std::unique_lock<std::mutex> lock(_mutex);
|
std::unique_lock<std::mutex> lock(_mutex);
|
||||||
_serverThread = std::thread([this]() {
|
_serverThread =
|
||||||
if (!_server.bind_to_port("localhost", tokenGrabberPort, 0)) {
|
std::thread([this]() { _server.listen("localhost", 8080); });
|
||||||
blog(LOG_WARNING,
|
|
||||||
"Failed to bind token server to localhost %d!",
|
|
||||||
tokenGrabberPort);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!_server.listen_after_bind()) {
|
|
||||||
blog(LOG_WARNING, "Token server failed to listen()!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
vblog(LOG_INFO, "Token server stopped!");
|
|
||||||
});
|
|
||||||
auto time = std::chrono::high_resolution_clock::now() +
|
auto time = std::chrono::high_resolution_clock::now() +
|
||||||
std::chrono::seconds(_timeout);
|
std::chrono::seconds(_timeout);
|
||||||
while (!_stopWaiting) {
|
while (!_stopWaiting) {
|
||||||
|
|||||||
@@ -1,18 +1,11 @@
|
|||||||
#include "twitch-helpers.hpp"
|
#include "twitch-helpers.hpp"
|
||||||
#include "token.hpp"
|
#include "token.hpp"
|
||||||
|
|
||||||
#include <log-helper.hpp>
|
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
static constexpr std::string_view clientID = "ds5tt4ogliifsqc04mz3d3etnck3e5";
|
static constexpr std::string_view clientID = "ds5tt4ogliifsqc04mz3d3etnck3e5";
|
||||||
static const int cacheTimeoutSeconds = 10;
|
static const int cacheTimeoutSeconds = 10;
|
||||||
|
|
||||||
const char *GetClientID()
|
|
||||||
{
|
|
||||||
return clientID.data();
|
|
||||||
}
|
|
||||||
|
|
||||||
class Args {
|
class Args {
|
||||||
public:
|
public:
|
||||||
Args(const std::string &uri, const std::string &path,
|
Args(const std::string &uri, const std::string &path,
|
||||||
@@ -50,7 +43,7 @@ struct CacheEntry {
|
|||||||
std::chrono::system_clock::now();
|
std::chrono::system_clock::now();
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool cacheIsTooOld(const CacheEntry &cache)
|
static bool chacheIsTooOld(const CacheEntry &cache)
|
||||||
{
|
{
|
||||||
auto currentTime = std::chrono::system_clock::now();
|
auto currentTime = std::chrono::system_clock::now();
|
||||||
auto diff = currentTime - cache.cacheTime;
|
auto diff = currentTime - cache.cacheTime;
|
||||||
@@ -61,7 +54,7 @@ static bool cacheIsValid(const std::map<Args, CacheEntry> &cache,
|
|||||||
const Args &args)
|
const Args &args)
|
||||||
{
|
{
|
||||||
auto it = cache.find(args);
|
auto it = cache.find(args);
|
||||||
return it != cache.end() && !cacheIsTooOld(it->second);
|
return it != cache.end() && !chacheIsTooOld(it->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
static httplib::Headers getTokenRequestHeaders(const std::string &token)
|
static httplib::Headers getTokenRequestHeaders(const std::string &token)
|
||||||
@@ -72,262 +65,166 @@ static httplib::Headers getTokenRequestHeaders(const std::string &token)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string getRequestBody(const OBSData &data)
|
RequestResult SendGetRequest(const std::string &uri, const std::string &path,
|
||||||
{
|
const TwitchToken &token,
|
||||||
auto json = obs_data_get_json(data);
|
|
||||||
return json ? json : "";
|
|
||||||
}
|
|
||||||
|
|
||||||
static RequestResult processResult(const httplib::Result &response,
|
|
||||||
const char *funcName)
|
|
||||||
{
|
|
||||||
if (!response) {
|
|
||||||
auto err = response.error();
|
|
||||||
blog(LOG_WARNING, "Twitch request failed in %s with error: %s",
|
|
||||||
funcName, httplib::to_string(err).c_str());
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
RequestResult result;
|
|
||||||
result.status = response->status;
|
|
||||||
|
|
||||||
if (response->body.empty()) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
OBSDataAutoRelease replyData =
|
|
||||||
obs_data_create_from_json(response->body.c_str());
|
|
||||||
result.data = replyData;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
RequestResult SendGetRequest(const TwitchToken &token, const std::string &uri,
|
|
||||||
const std::string &path,
|
|
||||||
const httplib::Params ¶ms)
|
const httplib::Params ¶ms)
|
||||||
{
|
{
|
||||||
httplib::Client cli(uri);
|
httplib::Client cli(uri);
|
||||||
auto tokenStr = token.GetToken();
|
auto tokenStr = token.GetToken();
|
||||||
|
|
||||||
if (!tokenStr) {
|
if (!tokenStr) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto url = httplib::append_query_params(uri + path, params);
|
|
||||||
vblog(LOG_INFO, "Twitch GET request to %s began", url.c_str());
|
|
||||||
|
|
||||||
auto headers = getTokenRequestHeaders(*tokenStr);
|
auto headers = getTokenRequestHeaders(*tokenStr);
|
||||||
auto response = cli.Get(path, params, headers);
|
auto response = cli.Get(path, params, headers);
|
||||||
|
if (!response) {
|
||||||
return processResult(response, __func__);
|
auto err = response.error();
|
||||||
|
blog(LOG_INFO, "%s failed - %s", __func__,
|
||||||
|
httplib::to_string(err).c_str());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
RequestResult result;
|
||||||
|
result.status = response->status;
|
||||||
|
if (response->body.empty()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
OBSDataAutoRelease replyData =
|
||||||
|
obs_data_create_from_json(response->body.c_str());
|
||||||
|
result.data = replyData;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
RequestResult SendGetRequest(const TwitchToken &token, const std::string &uri,
|
RequestResult SendGetRequest(const std::string &uri, const std::string &path,
|
||||||
const std::string &path,
|
const TwitchToken &token,
|
||||||
const httplib::Params ¶ms, bool useCache)
|
const httplib::Params ¶ms, bool useCache)
|
||||||
{
|
{
|
||||||
static std::map<Args, CacheEntry> cache;
|
static std::map<Args, CacheEntry> cache;
|
||||||
static std::mutex mtx;
|
static std::mutex mtx;
|
||||||
std::lock_guard<std::mutex> lock(mtx);
|
std::lock_guard<std::mutex> lock(mtx);
|
||||||
auto tokenStr = token.GetToken();
|
auto tokenStr = token.GetToken();
|
||||||
|
|
||||||
if (!tokenStr) {
|
if (!tokenStr) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto headers = getTokenRequestHeaders(*tokenStr);
|
auto headers = getTokenRequestHeaders(*tokenStr);
|
||||||
Args args(uri, path, "", params, headers);
|
Args args(uri, path, "", params, headers);
|
||||||
|
|
||||||
if (useCache && cacheIsValid(cache, args)) {
|
if (useCache && cacheIsValid(cache, args)) {
|
||||||
auto it = cache.find(args);
|
auto it = cache.find(args);
|
||||||
return it->second.result;
|
return it->second.result;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto result = SendGetRequest(token, uri, path, params);
|
auto result = SendGetRequest(uri, path, token, params);
|
||||||
cache[args] = {result};
|
cache[args] = {result};
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
RequestResult SendPostRequest(const TwitchToken &token, const std::string &uri,
|
RequestResult SendPostRequest(const std::string &uri, const std::string &path,
|
||||||
const std::string &path,
|
const TwitchToken &token, const OBSData &data)
|
||||||
const httplib::Params ¶ms,
|
|
||||||
const OBSData &data)
|
|
||||||
{
|
{
|
||||||
httplib::Client cli(uri);
|
httplib::Client cli(uri);
|
||||||
auto tokenStr = token.GetToken();
|
auto tokenStr = token.GetToken();
|
||||||
|
|
||||||
if (!tokenStr) {
|
if (!tokenStr) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pathWithParams = httplib::append_query_params(path, params);
|
|
||||||
auto url = uri + pathWithParams;
|
|
||||||
vblog(LOG_INFO, "Twitch POST request to %s began", url.c_str());
|
|
||||||
|
|
||||||
auto headers = getTokenRequestHeaders(*tokenStr);
|
auto headers = getTokenRequestHeaders(*tokenStr);
|
||||||
auto body = getRequestBody(data);
|
auto json = obs_data_get_json(data);
|
||||||
auto response =
|
std::string body = json ? json : "";
|
||||||
cli.Post(pathWithParams, headers, body, "application/json");
|
auto response = cli.Post(path, headers, body, "application/json");
|
||||||
|
if (!response) {
|
||||||
return processResult(response, __func__);
|
auto err = response.error();
|
||||||
|
blog(LOG_INFO, "%s failed - %s", __func__,
|
||||||
|
httplib::to_string(err).c_str());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
RequestResult result;
|
||||||
|
result.status = response->status;
|
||||||
|
if (response->body.empty()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
OBSDataAutoRelease replyData =
|
||||||
|
obs_data_create_from_json(response->body.c_str());
|
||||||
|
result.data = replyData;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
RequestResult SendPostRequest(const TwitchToken &token, const std::string &uri,
|
RequestResult SendPostRequest(const std::string &uri, const std::string &path,
|
||||||
const std::string &path,
|
const TwitchToken &token, const OBSData &data,
|
||||||
const httplib::Params ¶ms,
|
bool useCache)
|
||||||
const OBSData &data, bool useCache)
|
|
||||||
{
|
{
|
||||||
static std::map<Args, CacheEntry> cache;
|
static std::map<Args, CacheEntry> cache;
|
||||||
static std::mutex mtx;
|
static std::mutex mtx;
|
||||||
std::lock_guard<std::mutex> lock(mtx);
|
std::lock_guard<std::mutex> lock(mtx);
|
||||||
auto tokenStr = token.GetToken();
|
auto tokenStr = token.GetToken();
|
||||||
|
|
||||||
if (!tokenStr) {
|
if (!tokenStr) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto headers = getTokenRequestHeaders(*tokenStr);
|
auto headers = getTokenRequestHeaders(*tokenStr);
|
||||||
auto body = getRequestBody(data);
|
auto jsonCstr = obs_data_get_json(data);
|
||||||
Args args(uri, path, body, params, headers);
|
Args args(uri, path, jsonCstr ? jsonCstr : "", {}, headers);
|
||||||
|
|
||||||
if (useCache && cacheIsValid(cache, args)) {
|
if (useCache && cacheIsValid(cache, args)) {
|
||||||
auto it = cache.find(args);
|
auto it = cache.find(args);
|
||||||
return it->second.result;
|
return it->second.result;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto result = SendPostRequest(token, uri, path, params, data);
|
auto result = SendPostRequest(uri, path, token, data);
|
||||||
cache[args] = {result};
|
cache[args] = {result};
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
RequestResult SendPutRequest(const TwitchToken &token, const std::string &uri,
|
RequestResult SendPatchRequest(const std::string &uri, const std::string &path,
|
||||||
const std::string &path,
|
const TwitchToken &token, const OBSData &data)
|
||||||
const httplib::Params ¶ms, const OBSData &data)
|
|
||||||
{
|
{
|
||||||
httplib::Client cli(uri);
|
httplib::Client cli(uri);
|
||||||
auto tokenStr = token.GetToken();
|
auto tokenStr = token.GetToken();
|
||||||
|
|
||||||
if (!tokenStr) {
|
if (!tokenStr) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pathWithParams = httplib::append_query_params(path, params);
|
|
||||||
auto url = uri + pathWithParams;
|
|
||||||
vblog(LOG_INFO, "Twitch PUT request to %s began", url.c_str());
|
|
||||||
|
|
||||||
auto headers = getTokenRequestHeaders(*tokenStr);
|
auto headers = getTokenRequestHeaders(*tokenStr);
|
||||||
auto body = getRequestBody(data);
|
auto json = obs_data_get_json(data);
|
||||||
auto response =
|
std::string body = json ? json : "";
|
||||||
cli.Put(pathWithParams, headers, body, "application/json");
|
auto response = cli.Patch(path, headers, body, "application/json");
|
||||||
|
if (!response) {
|
||||||
return processResult(response, __func__);
|
auto err = response.error();
|
||||||
|
blog(LOG_INFO, "%s failed - %s", __func__,
|
||||||
|
httplib::to_string(err).c_str());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
RequestResult result;
|
||||||
|
result.status = response->status;
|
||||||
|
if (response->body.empty()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
OBSDataAutoRelease replyData =
|
||||||
|
obs_data_create_from_json(response->body.c_str());
|
||||||
|
result.data = replyData;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
RequestResult SendPutRequest(const TwitchToken &token, const std::string &uri,
|
RequestResult SendPatchRequest(const std::string &uri, const std::string &path,
|
||||||
const std::string &path,
|
const TwitchToken &token, const OBSData &data,
|
||||||
const httplib::Params ¶ms, const OBSData &data,
|
bool useCache)
|
||||||
bool useCache)
|
|
||||||
{
|
{
|
||||||
static std::map<Args, CacheEntry> cache;
|
static std::map<Args, CacheEntry> cache;
|
||||||
static std::mutex mtx;
|
static std::mutex mtx;
|
||||||
std::lock_guard<std::mutex> lock(mtx);
|
std::lock_guard<std::mutex> lock(mtx);
|
||||||
auto tokenStr = token.GetToken();
|
auto tokenStr = token.GetToken();
|
||||||
|
|
||||||
if (!tokenStr) {
|
if (!tokenStr) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto headers = getTokenRequestHeaders(*tokenStr);
|
auto headers = getTokenRequestHeaders(*tokenStr);
|
||||||
auto body = getRequestBody(data);
|
auto jsonCstr = obs_data_get_json(data);
|
||||||
Args args(uri, path, body, params, headers);
|
Args args(uri, path, jsonCstr ? jsonCstr : "", {}, headers);
|
||||||
|
|
||||||
if (useCache && cacheIsValid(cache, args)) {
|
if (useCache && cacheIsValid(cache, args)) {
|
||||||
auto it = cache.find(args);
|
auto it = cache.find(args);
|
||||||
return it->second.result;
|
return it->second.result;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto result = SendPutRequest(token, uri, path, params, data);
|
auto result = SendPatchRequest(uri, path, token, data);
|
||||||
cache[args] = {result};
|
cache[args] = {result};
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
RequestResult SendPatchRequest(const TwitchToken &token, const std::string &uri,
|
const char *GetClientID()
|
||||||
const std::string &path,
|
|
||||||
const httplib::Params ¶ms,
|
|
||||||
const OBSData &data)
|
|
||||||
{
|
{
|
||||||
httplib::Client cli(uri);
|
return clientID.data();
|
||||||
auto tokenStr = token.GetToken();
|
|
||||||
|
|
||||||
if (!tokenStr) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto pathWithParams = httplib::append_query_params(path, params);
|
|
||||||
auto url = uri + pathWithParams;
|
|
||||||
vblog(LOG_INFO, "Twitch PATCH request to %s began", url.c_str());
|
|
||||||
|
|
||||||
auto headers = getTokenRequestHeaders(*tokenStr);
|
|
||||||
auto body = getRequestBody(data);
|
|
||||||
auto response =
|
|
||||||
cli.Patch(pathWithParams, headers, body, "application/json");
|
|
||||||
|
|
||||||
return processResult(response, __func__);
|
|
||||||
}
|
|
||||||
|
|
||||||
RequestResult SendPatchRequest(const TwitchToken &token, const std::string &uri,
|
|
||||||
const std::string &path,
|
|
||||||
const httplib::Params ¶ms,
|
|
||||||
const OBSData &data, bool useCache)
|
|
||||||
{
|
|
||||||
static std::map<Args, CacheEntry> cache;
|
|
||||||
static std::mutex mtx;
|
|
||||||
std::lock_guard<std::mutex> lock(mtx);
|
|
||||||
auto tokenStr = token.GetToken();
|
|
||||||
|
|
||||||
if (!tokenStr) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto headers = getTokenRequestHeaders(*tokenStr);
|
|
||||||
auto body = getRequestBody(data);
|
|
||||||
Args args(uri, path, body, params, headers);
|
|
||||||
|
|
||||||
if (useCache && cacheIsValid(cache, args)) {
|
|
||||||
auto it = cache.find(args);
|
|
||||||
return it->second.result;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto result = SendPatchRequest(token, uri, path, params, data);
|
|
||||||
cache[args] = {result};
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
RequestResult SendDeleteRequest(const TwitchToken &token,
|
|
||||||
const std::string &uri, const std::string &path,
|
|
||||||
const httplib::Params ¶ms)
|
|
||||||
{
|
|
||||||
httplib::Client cli(uri);
|
|
||||||
auto tokenStr = token.GetToken();
|
|
||||||
|
|
||||||
if (!tokenStr) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto pathWithParams = httplib::append_query_params(path, params);
|
|
||||||
auto url = uri + pathWithParams;
|
|
||||||
vblog(LOG_INFO, "Twitch DELETE request to %s began", url.c_str());
|
|
||||||
|
|
||||||
auto headers = getTokenRequestHeaders(*tokenStr);
|
|
||||||
auto response =
|
|
||||||
cli.Delete(pathWithParams, headers, "", "application/json");
|
|
||||||
|
|
||||||
return processResult(response, __func__);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -13,44 +13,29 @@ struct RequestResult {
|
|||||||
OBSData data = nullptr;
|
OBSData data = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *GetClientID();
|
|
||||||
|
|
||||||
// These functions do *not* use or create RequestResult cache entries
|
// These functions do *not* use or create RequestResult cache entries
|
||||||
RequestResult SendGetRequest(const TwitchToken &token, const std::string &uri,
|
|
||||||
const std::string &path,
|
RequestResult SendGetRequest(const std::string &uri, const std::string &path,
|
||||||
const httplib::Params ¶ms = {});
|
const TwitchToken &token,
|
||||||
RequestResult SendPostRequest(const TwitchToken &token, const std::string &uri,
|
const httplib::Params & = {});
|
||||||
const std::string &path,
|
RequestResult SendPostRequest(const std::string &uri, const std::string &path,
|
||||||
const httplib::Params ¶ms = {},
|
const TwitchToken &token, const OBSData &data);
|
||||||
const OBSData &data = nullptr);
|
RequestResult SendPatchRequest(const std::string &uri, const std::string &path,
|
||||||
RequestResult SendPutRequest(const TwitchToken &token, const std::string &uri,
|
const TwitchToken &token, const OBSData &data);
|
||||||
const std::string &path,
|
|
||||||
const httplib::Params ¶ms = {},
|
|
||||||
const OBSData &data = nullptr);
|
|
||||||
RequestResult SendPatchRequest(const TwitchToken &token, const std::string &uri,
|
|
||||||
const std::string &path,
|
|
||||||
const httplib::Params ¶ms = {},
|
|
||||||
const OBSData &data = nullptr);
|
|
||||||
RequestResult SendDeleteRequest(const TwitchToken &token,
|
|
||||||
const std::string &uri, const std::string &path,
|
|
||||||
const httplib::Params ¶ms = {});
|
|
||||||
|
|
||||||
// These functions will cache the RequestResult for 10s
|
// These functions will cache the RequestResult for 10s
|
||||||
// Note that the cache will be reported as a "memory leak" on OBS shutdown
|
// Note that the cache will be reported as a "memory leak" on OBS shutdown
|
||||||
RequestResult SendGetRequest(const TwitchToken &token, const std::string &uri,
|
|
||||||
const std::string &path,
|
RequestResult SendGetRequest(const std::string &uri, const std::string &path,
|
||||||
const httplib::Params ¶ms, bool useCache);
|
const TwitchToken &token, const httplib::Params &,
|
||||||
RequestResult SendPostRequest(const TwitchToken &token, const std::string &uri,
|
|
||||||
const std::string &path,
|
|
||||||
const httplib::Params ¶ms,
|
|
||||||
const OBSData &data, bool useCache);
|
|
||||||
RequestResult SendPutRequest(const TwitchToken &token, const std::string &uri,
|
|
||||||
const std::string &path,
|
|
||||||
const httplib::Params ¶ms, const OBSData &data,
|
|
||||||
bool useCache);
|
bool useCache);
|
||||||
RequestResult SendPatchRequest(const TwitchToken &token, const std::string &uri,
|
RequestResult SendPostRequest(const std::string &uri, const std::string &path,
|
||||||
const std::string &path,
|
const TwitchToken &token, const OBSData &data,
|
||||||
const httplib::Params ¶ms,
|
bool useCache);
|
||||||
const OBSData &data, bool useCache);
|
RequestResult SendPatchRequest(const std::string &uri, const std::string &path,
|
||||||
|
const TwitchToken &token, const OBSData &data,
|
||||||
|
bool useCache);
|
||||||
|
|
||||||
|
const char *GetClientID();
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user