mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-09-07 09:05:57 -05:00
Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9305576789 | ||
|
|
38bd59c1fd | ||
|
|
7f84de64d8 | ||
|
|
5ae90fe913 | ||
|
|
115a90196c | ||
|
|
5e92a7bcdf | ||
|
|
922cf95119 | ||
|
|
05540b61a1 | ||
|
|
218ad13160 | ||
|
|
6e18eebb25 | ||
|
|
b7058f97a9 | ||
|
|
b0c00dfa98 | ||
|
|
7a074aa548 | ||
|
|
51c740bdc6 | ||
|
|
826a25926c | ||
|
|
e2cd39315f | ||
|
|
7665bf8872 | ||
|
|
14d78100c1 | ||
|
|
92d75bbddb | ||
|
|
14d6e6f5bf | ||
|
|
78fa18f22a | ||
|
|
bbf7d4acf5 | ||
|
|
299f7c00e0 | ||
|
|
70c0a8ed57 | ||
|
|
d41868c660 | ||
|
|
3381e6d62f | ||
|
|
6338aaa891 | ||
|
|
104f74bf39 | ||
|
|
9cc2875455 | ||
|
|
e466bf9750 | ||
|
|
42dcd9dec4 | ||
|
|
c934b5c7ff | ||
|
|
dd2d70bb9c | ||
|
|
ad052e9323 | ||
|
|
086d07f678 | ||
|
|
c606869d41 | ||
|
|
12512f7d0a | ||
|
|
1ed924a39c | ||
|
|
59ed240311 | ||
|
|
712767b824 | ||
|
|
bb4035824b | ||
|
|
a1d385f5dc | ||
|
|
3c9b1f7ad8 | ||
|
|
fc66509e50 | ||
|
|
62f1109256 | ||
|
|
25540aee2b | ||
|
|
53aa828c9e |
98
.gitignore
vendored
Normal file
98
.gitignore
vendored
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
# Prerequisites #
|
||||||
|
#################
|
||||||
|
*.d
|
||||||
|
|
||||||
|
# Object files #
|
||||||
|
################
|
||||||
|
*.o
|
||||||
|
*.ko
|
||||||
|
*.obj
|
||||||
|
*.elf
|
||||||
|
*.slo
|
||||||
|
*.lo
|
||||||
|
*.obj
|
||||||
|
|
||||||
|
# Linker output #
|
||||||
|
#################
|
||||||
|
*.ilk
|
||||||
|
*.map
|
||||||
|
*.exp
|
||||||
|
|
||||||
|
# Precompiled Headers #
|
||||||
|
#######################
|
||||||
|
*.gch
|
||||||
|
*.pch
|
||||||
|
|
||||||
|
# Libraries #
|
||||||
|
#############
|
||||||
|
*.lib
|
||||||
|
*.a
|
||||||
|
*.la
|
||||||
|
*.lo
|
||||||
|
*.lai
|
||||||
|
|
||||||
|
# Shared objects (inc. Windows DLLs) #
|
||||||
|
######################################
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.so.*
|
||||||
|
*.dylib
|
||||||
|
|
||||||
|
# Executables #
|
||||||
|
###############
|
||||||
|
*.exe
|
||||||
|
*.out
|
||||||
|
*.app
|
||||||
|
*.i*86
|
||||||
|
*.x86_64
|
||||||
|
*.hex
|
||||||
|
|
||||||
|
# Debug files #
|
||||||
|
###############
|
||||||
|
*.dSYM/
|
||||||
|
*.su
|
||||||
|
*.idb
|
||||||
|
*.pdb
|
||||||
|
|
||||||
|
# CMake temp files #
|
||||||
|
####################
|
||||||
|
CMakeLists.txt.user
|
||||||
|
CMakeCache.txt
|
||||||
|
CMakeFiles
|
||||||
|
CMakeScripts
|
||||||
|
Testing
|
||||||
|
Makefile
|
||||||
|
cmake_install.cmake
|
||||||
|
install_manifest.txt
|
||||||
|
compile_commands.json
|
||||||
|
CTestTestfile.cmake_install
|
||||||
|
|
||||||
|
# OS generated files #
|
||||||
|
######################
|
||||||
|
.DS_Store
|
||||||
|
.DS_Store?
|
||||||
|
._*
|
||||||
|
.Spotlight-V100
|
||||||
|
.Trashes
|
||||||
|
ehthumbs.db
|
||||||
|
Thumbs.db
|
||||||
|
*.directory
|
||||||
|
|
||||||
|
# backup text files generated by an editor #
|
||||||
|
############################################
|
||||||
|
**/*~
|
||||||
|
|
||||||
|
# Various IDE Files #
|
||||||
|
#####################
|
||||||
|
.classpath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.idea
|
||||||
|
.metadata
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.sublime*
|
||||||
|
|
||||||
|
# Directories #
|
||||||
|
###############
|
||||||
|
build/
|
||||||
298
CMakeLists.txt
298
CMakeLists.txt
@@ -1,77 +1,227 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
project(advanced-scene-switcher)
|
project(advanced-scene-switcher)
|
||||||
|
|
||||||
if(APPLE)
|
if(BUILD_OUT_OF_TREE)
|
||||||
find_library(COCOA Cocoa)
|
# out of tree builds
|
||||||
include_directories(${COCOA})
|
# credits to c3r1c3
|
||||||
|
set(CMAKE_PREFIX_PATH "${QTDIR}")
|
||||||
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/external")
|
||||||
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
set(CMAKE_AUTOUIC ON)
|
||||||
|
|
||||||
|
|
||||||
|
include(external/FindLibObs.cmake)
|
||||||
|
find_package(LibObs REQUIRED)
|
||||||
|
find_package(Qt5Core REQUIRED)
|
||||||
|
find_package(Qt5Widgets REQUIRED)
|
||||||
|
find_path(LIBOBS_FRONTEND_INCLUDE_DIR HINTS ${LIBOBS_INCLUDE_DIRS})
|
||||||
|
find_file(LIBOBS_FRONTEND_API_LIB NAMES libobs-frontend-api.* HINTS ${LIBOBS_LIB} )
|
||||||
|
|
||||||
|
if(APPLE)
|
||||||
|
find_library(COCOA Cocoa)
|
||||||
|
find_package(Qt5MacExtras REQUIRED)
|
||||||
|
include_directories(${COCOA})
|
||||||
|
add_link_options("-v")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(UNIX AND NOT APPLE)
|
||||||
|
find_package(X11 REQUIRED)
|
||||||
|
link_libraries(${X11_LIBRARIES})
|
||||||
|
include_directories(${X11_INCLUDE_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(advanced-scene-switcher_HEADERS
|
||||||
|
${advanced-scene-switcher_HEADERS}
|
||||||
|
src/headers/advanced-scene-switcher.hpp
|
||||||
|
src/headers/switcher-data-structs.hpp
|
||||||
|
src/headers/utility.hpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(advanced-scene-switcher_SOURCES
|
||||||
|
${advanced-scene-switcher_SOURCES}
|
||||||
|
src/advanced-scene-switcher.cpp
|
||||||
|
src/advanced-scene-switcher-module.c
|
||||||
|
src/scene-transitions.cpp
|
||||||
|
src/screen-region-switch.cpp
|
||||||
|
src/priority.cpp
|
||||||
|
src/executable-switch.cpp
|
||||||
|
src/idle-switch.cpp
|
||||||
|
src/scene-round-trip.cpp
|
||||||
|
src/file-switch.cpp
|
||||||
|
src/window-title-switch.cpp
|
||||||
|
src/media-switch.cpp
|
||||||
|
src/hotkey.cpp
|
||||||
|
src/general.cpp
|
||||||
|
src/pause-switch.cpp
|
||||||
|
src/random.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(advanced-scene-switcher_UI
|
||||||
|
${advanced-scene-switcher_UI}
|
||||||
|
forms/advanced-scene-switcher.ui
|
||||||
|
)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
set(advanced-scene-switcher_PLATFORM_SOURCES
|
||||||
|
src/win/advanced-scene-switcher-win.cpp)
|
||||||
|
|
||||||
|
elseif(APPLE)
|
||||||
|
set(advanced-scene-switcher_PLATFORM_SOURCES
|
||||||
|
src/osx/advanced-scene-switcher-osx.mm)
|
||||||
|
set_source_files_properties(advanced-scene-switcher-osx.mm
|
||||||
|
PROPERTIES COMPILE_FLAGS "-fobjc-arc")
|
||||||
|
set(advanced-scene-switcher_PLATFORM_LIBS
|
||||||
|
${COCOA})
|
||||||
|
|
||||||
|
elseif("${CMAKE_SYSTEM_NAME}" MATCHES "Linux")
|
||||||
|
set(advanced-scene-switcher_PLATFORM_SOURCES
|
||||||
|
src/linux/advanced-scene-switcher-nix.cpp)
|
||||||
|
set(advanced-scene-switcher_PLATFORM_LIBS
|
||||||
|
Xss)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_library(advanced-scene-switcher MODULE
|
||||||
|
${advanced-scene-switcher_HEADERS}
|
||||||
|
${advanced-scene-switcher_SOURCES}
|
||||||
|
${advanced-scene-switcher_UI_HEADERS}
|
||||||
|
${advanced-scene-switcher_PLATFORM_SOURCES}
|
||||||
|
${advanced-scene-switcher_PLATFORM_HEADERS}
|
||||||
|
)
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
"${LIBOBS_INCLUDE_DIRS}"
|
||||||
|
"${LIBOBS_FRONTEND_INCLUDE_DIR}"
|
||||||
|
${Qt5Core_INCLUDES}
|
||||||
|
${Qt5Widgets_INCLUDES})
|
||||||
|
|
||||||
|
target_link_libraries(advanced-scene-switcher
|
||||||
|
${advanced-scene-switcher_PLATFORM_LIBS}
|
||||||
|
${LIBOBS_LIB}
|
||||||
|
${LIBOBS_FRONTEND_API_LIB}
|
||||||
|
Qt5::Core
|
||||||
|
Qt5::Widgets)
|
||||||
|
|
||||||
|
# Additional commands to install the module in the correct place.
|
||||||
|
# Find all the translation files so we can copy them to the correct
|
||||||
|
# place later on.
|
||||||
|
file(GLOB ASS_TRANSLATION_FILES
|
||||||
|
"data/locale/*.ini"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Windows
|
||||||
|
if(WIN32)
|
||||||
|
string(REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
|
||||||
|
message("${CMAKE_CXX_FLAGS_RELEASE}")
|
||||||
|
|
||||||
|
find_package(w32-pthreads REQUIRED)
|
||||||
|
|
||||||
|
target_link_libraries(advanced-scene-switcher
|
||||||
|
w32-pthreads)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# OSX
|
||||||
|
if(APPLE)
|
||||||
|
set_target_properties(advanced-scene-switcher PROPERTIES PREFIX "")
|
||||||
|
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Linux
|
||||||
|
if(UNIX AND NOT APPLE)
|
||||||
|
set(CMAKE_C_FLAGS "-Wall -Wextra -Wvla -Wno-unused-function -Werror-implicit-function-declaration -Wno-missing-braces -Wno-missing-field-initializers ${CMAKE_C_FLAGS} -std=c99 -fno-strict-aliasing")
|
||||||
|
|
||||||
|
if(ARCH EQUAL 64)
|
||||||
|
set(ARCH_NAME "x86_64")
|
||||||
|
else()
|
||||||
|
set(ARCH_NAME "i686")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set_target_properties(advanced-scene-switcher PROPERTIES PREFIX "")
|
||||||
|
|
||||||
|
install(TARGETS advanced-scene-switcher
|
||||||
|
LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/obs-plugins)
|
||||||
|
install(FILES ${ASS_TRANSLATION_FILES}
|
||||||
|
DESTINATION "${CMAKE_INSTALL_PREFIX}/share/obs/obs-plugins/advanced-scene-switcher/locale")
|
||||||
|
endif()
|
||||||
|
else ()
|
||||||
|
# in-tree build
|
||||||
|
if(APPLE)
|
||||||
|
find_library(COCOA Cocoa)
|
||||||
|
include_directories(${COCOA})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(UNIX)
|
||||||
|
find_package(X11 REQUIRED)
|
||||||
|
link_libraries(${X11_LIBRARIES})
|
||||||
|
include_directories(${X11_INCLUDE_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(advanced-scene-switcher_HEADERS
|
||||||
|
${advanced-scene-switcher_HEADERS}
|
||||||
|
src/headers/advanced-scene-switcher.hpp
|
||||||
|
src/headers/switcher-data-structs.hpp
|
||||||
|
src/headers/utility.hpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(advanced-scene-switcher_SOURCES
|
||||||
|
${advanced-scene-switcher_SOURCES}
|
||||||
|
src/advanced-scene-switcher.cpp
|
||||||
|
src/advanced-scene-switcher-module.c
|
||||||
|
src/scene-transitions.cpp
|
||||||
|
src/screen-region-switch.cpp
|
||||||
|
src/priority.cpp
|
||||||
|
src/executable-switch.cpp
|
||||||
|
src/idle-switch.cpp
|
||||||
|
src/scene-round-trip.cpp
|
||||||
|
src/file-switch.cpp
|
||||||
|
src/window-title-switch.cpp
|
||||||
|
src/media-switch.cpp
|
||||||
|
src/hotkey.cpp
|
||||||
|
src/general.cpp
|
||||||
|
src/pause-switch.cpp
|
||||||
|
src/random.cpp
|
||||||
|
)
|
||||||
|
set(advanced-scene-switcher_UI
|
||||||
|
${advanced-scene-switcher_UI}
|
||||||
|
forms/advanced-scene-switcher.ui
|
||||||
|
)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
set(advanced-scene-switcher_PLATFORM_SOURCES
|
||||||
|
src/win/advanced-scene-switcher-win.cpp)
|
||||||
|
|
||||||
|
elseif(APPLE)
|
||||||
|
set(advanced-scene-switcher_PLATFORM_SOURCES
|
||||||
|
src/osx/advanced-scene-switcher-osx.mm)
|
||||||
|
set_source_files_properties(advanced-scene-switcher-osx.mm
|
||||||
|
PROPERTIES COMPILE_FLAGS "-fobjc-arc")
|
||||||
|
|
||||||
|
set(advanced-scene-switcher_PLATFORM_LIBS
|
||||||
|
${COCOA})
|
||||||
|
else()
|
||||||
|
set(advanced-scene-switcher_PLATFORM_SOURCES
|
||||||
|
src/linux/advanced-scene-switcher-nix.cpp)
|
||||||
|
set(advanced-scene-switcher_PLATFORM_LIBS
|
||||||
|
Xss)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
qt5_wrap_ui(advanced-scene-switcher_UI_HEADERS
|
||||||
|
${advanced-scene-switcher_UI}
|
||||||
|
${advanced-scene-switcher_PLATFORM_UI})
|
||||||
|
|
||||||
|
add_library(advanced-scene-switcher MODULE
|
||||||
|
${advanced-scene-switcher_HEADERS}
|
||||||
|
${advanced-scene-switcher_SOURCES}
|
||||||
|
${advanced-scene-switcher_UI_HEADERS}
|
||||||
|
${advanced-scene-switcher_PLATFORM_SOURCES}
|
||||||
|
${advanced-scene-switcher_PLATFORM_HEADERS}
|
||||||
|
)
|
||||||
|
target_link_libraries(advanced-scene-switcher
|
||||||
|
${advanced-scene-switcher_PLATFORM_LIBS}
|
||||||
|
obs-frontend-api
|
||||||
|
Qt5::Widgets
|
||||||
|
libobs)
|
||||||
|
|
||||||
|
install_obs_plugin(advanced-scene-switcher data)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(UNIX)
|
|
||||||
find_package(X11 REQUIRED)
|
|
||||||
link_libraries(${X11_LIBRARIES})
|
|
||||||
include_directories(${X11_INCLUDE_DIR})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(advanced-scene-switcher_HEADERS
|
|
||||||
${advanced-scene-switcher_HEADERS}
|
|
||||||
advanced-scene-switcher.hpp
|
|
||||||
switcher-data-structs.hpp
|
|
||||||
utility.hpp
|
|
||||||
)
|
|
||||||
set(advanced-scene-switcher_SOURCES
|
|
||||||
${advanced-scene-switcher_SOURCES}
|
|
||||||
advanced-scene-switcher.cpp
|
|
||||||
advanced-scene-switcher-module.c
|
|
||||||
scene-transitions.cpp
|
|
||||||
screen-region-switch.cpp
|
|
||||||
priority.cpp
|
|
||||||
executable-switch.cpp
|
|
||||||
idle-switch.cpp
|
|
||||||
scene-round-trip.cpp
|
|
||||||
file-switch.cpp
|
|
||||||
window-title-switch.cpp
|
|
||||||
hotkey.cpp
|
|
||||||
general.cpp
|
|
||||||
pause-switch.cpp
|
|
||||||
)
|
|
||||||
set(advanced-scene-switcher_UI
|
|
||||||
${advanced-scene-switcher_UI}
|
|
||||||
forms/advanced-scene-switcher.ui
|
|
||||||
)
|
|
||||||
|
|
||||||
if(WIN32)
|
|
||||||
set(advanced-scene-switcher_PLATFORM_SOURCES
|
|
||||||
advanced-scene-switcher-win.cpp)
|
|
||||||
|
|
||||||
elseif(APPLE)
|
|
||||||
set(advanced-scene-switcher_PLATFORM_SOURCES
|
|
||||||
advanced-scene-switcher-osx.mm)
|
|
||||||
set_source_files_properties(advanced-scene-switcher-osx.mm
|
|
||||||
PROPERTIES COMPILE_FLAGS "-fobjc-arc")
|
|
||||||
|
|
||||||
set(advanced-scene-switcher_PLATFORM_LIBS
|
|
||||||
${COCOA})
|
|
||||||
else()
|
|
||||||
set(advanced-scene-switcher_PLATFORM_SOURCES
|
|
||||||
advanced-scene-switcher-nix.cpp)
|
|
||||||
set(advanced-scene-switcher_PLATFORM_LIBS
|
|
||||||
Xss)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
qt5_wrap_ui(advanced-scene-switcher_UI_HEADERS
|
|
||||||
${advanced-scene-switcher_UI}
|
|
||||||
${advanced-scene-switcher_PLATFORM_UI})
|
|
||||||
|
|
||||||
add_library(advanced-scene-switcher MODULE
|
|
||||||
${advanced-scene-switcher_HEADERS}
|
|
||||||
${advanced-scene-switcher_SOURCES}
|
|
||||||
${advanced-scene-switcher_UI_HEADERS}
|
|
||||||
${advanced-scene-switcher_PLATFORM_SOURCES}
|
|
||||||
${advanced-scene-switcher_PLATFORM_HEADERS}
|
|
||||||
)
|
|
||||||
target_link_libraries(advanced-scene-switcher
|
|
||||||
${advanced-scene-switcher_PLATFORM_LIBS}
|
|
||||||
obs-frontend-api
|
|
||||||
Qt5::Widgets
|
|
||||||
libobs)
|
|
||||||
|
|
||||||
install_obs_plugin_with_data(advanced-scene-switcher data)
|
|
||||||
|
|||||||
105
README.md
105
README.md
@@ -2,3 +2,108 @@
|
|||||||
An automated scene switcher for OBS Studio
|
An automated scene switcher for OBS Studio
|
||||||
|
|
||||||
More information can be found on https://obsproject.com/forum/resources/automatic-scene-switching.395/
|
More information can be found on https://obsproject.com/forum/resources/automatic-scene-switching.395/
|
||||||
|
|
||||||
|
## Compiling in tree
|
||||||
|
Add the "SceneSwitcher" source directory to your obs-studio source directory under obs-studio/UI/frontend-plugins/:
|
||||||
|
```
|
||||||
|
cd obs-studio/UI/frontend-plugins/
|
||||||
|
git clone https://github.com/WarmUpTill/SceneSwitcher.git
|
||||||
|
```
|
||||||
|
|
||||||
|
Then modify the obs-studio/UI/frontend-plugins/CMakeLists.txt file and add an entry for the scene switcher:
|
||||||
|
add_subdirectory(SceneSwitcher)
|
||||||
|
|
||||||
|
## Compiling out of tree
|
||||||
|
### Prerequisites
|
||||||
|
You'll need CMake and a working development environment for OBS Studio installed
|
||||||
|
on your computer. Once you've done that, do the following:
|
||||||
|
```
|
||||||
|
git clone https://github.com/WarmUpTill/SceneSwitcher.git
|
||||||
|
cd SceneSwitcher
|
||||||
|
mkdir build && cd build
|
||||||
|
```
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
In cmake-gui, you'll have to set these CMake variables :
|
||||||
|
- **BUILD_OUT_OF_TREE** (bool) : true
|
||||||
|
- **LIBOBS_INCLUDE_DIR** (path) : location of the libobs subfolder in the source
|
||||||
|
code of OBS Studio, located at [source_directory]/libobs/.
|
||||||
|
- **LIBOBS_LIB** (filepath) : location of the obs.dll file (usually set to
|
||||||
|
C:\Program Files\obs-studio\bin\64bit\obs.dll)
|
||||||
|
|
||||||
|
Assuming that you installed Qt via the regular Qt App way:
|
||||||
|
- **Qt5Core_DIR** (path) : C:/Qt/5.10.1/msvc2017_64/lib/cmake/Qt5Core
|
||||||
|
- **Qt5Gui_DIR** (path): C:/Qt/5.10.1/msvc2017_64/lib/cmake/Qt5Gui
|
||||||
|
- **Qt5Widgets_DIR** (path) : C:/Qt/5.10.1/msvc2017_64/lib/cmake/Qt5Widgets
|
||||||
|
|
||||||
|
- **LIBOBS_FRONTEND_API_LIB** (filepath) : location of the libobs-frontend-api.dll
|
||||||
|
file, usually C:/Program Files/obs-studio/bin/64bit/obs-frontend-api.dll
|
||||||
|
(usually in the same place as LIBOBS_LIB)
|
||||||
|
- **LIBOBS_FRONTEND_INCLUDE_DIR** (path) : location of the obs-frontend-api
|
||||||
|
subfolder in the source code of OBS Studio, located at [source_directory]/UI/obs-frontend-api.
|
||||||
|
|
||||||
|
Just keep hitting configure until all the vars are filled out. Then hit generate.
|
||||||
|
|
||||||
|
### Linux
|
||||||
|
Most versions of Linux you can use cmake-gui or the command line.
|
||||||
|
|
||||||
|
**For the command line:**
|
||||||
|
```
|
||||||
|
cmake -DBUILD_OUT_OF_TREE=1 -DLIBOBS_INCLUDE_DIR="<path to the libobs/ sub-folder in obs-studio's source code>"
|
||||||
|
-DLIBOBS_FRONTEND_INCLUDE_DIR="<path to the UI/obs-frontend-api/ sub-folder in obs-studio's source code>"
|
||||||
|
-DLIBOBS_FRONTEND_API_LIB="< path to the libobs-frontend-api.so file (usually in the same place as LIBOBS_LIB)>"
|
||||||
|
-DCMAKE_INSTALL_PREFIX=/usr ..
|
||||||
|
make -j4
|
||||||
|
sudo make install
|
||||||
|
```
|
||||||
|
|
||||||
|
For cmake-gui you'll have to set the following variables:
|
||||||
|
- **BUILD_OUT_OF_TREE** (bool) : true
|
||||||
|
- **LIBOBS_INCLUDE_DIR** (path) : location of the libobs subfolder in the source
|
||||||
|
code of OBS Studio, located at [source_directory]/libobs/.
|
||||||
|
- **LIBOBS_LIB** (filepath) : location of the libobs.so file (usually CMake finds
|
||||||
|
this, but if not it'll usually be in /usr/lib/libobs.so)
|
||||||
|
|
||||||
|
Assuming that you installed Qt via your system package manager, it should be
|
||||||
|
found automatically. If not, then usually you'll find it in something like:
|
||||||
|
- **Qt5Core_DIR** (path) : /usr/lib64/cmake/Qt5Core
|
||||||
|
- **Qt5Gui_DIR** (path): /usr/lib64/cmake/Qt5Gui
|
||||||
|
- **Qt5Widgets_DIR** (path) : /usr/lib64/cmake/Qt5Widgets
|
||||||
|
|
||||||
|
- **LIBOBS_FRONTEND_API_LIB** (filepath) : location of the libobs-frontend-api.so
|
||||||
|
file (usually in the same place as LIBOBS_LIB)
|
||||||
|
- **LIBOBS_FRONTEND_INCLUDE_DIR** (path) : location of the obs-frontend-api
|
||||||
|
subfolder in the source code of OBS Studio, located at
|
||||||
|
[source_directory]/UI/obs-frontend-api.
|
||||||
|
|
||||||
|
Just keep hitting configure until all the vars are filled out. Then hit generate.
|
||||||
|
|
||||||
|
Then open a terminal in the build folder and type:
|
||||||
|
```
|
||||||
|
make -j4
|
||||||
|
sudo make install
|
||||||
|
```
|
||||||
|
NOTE: The Linux version of this plugin is dependent on libXScrnSaver.
|
||||||
|
|
||||||
|
### OS X
|
||||||
|
In cmake-gui, you'll have to set these CMake variables :
|
||||||
|
- **BUILD_OUT_OF_TREE** (bool) : true
|
||||||
|
- **LIBOBS_INCLUDE_DIR** (path) : location of the libobs subfolder in the source
|
||||||
|
code of OBS Studio, located at [source_directory]/libobs/.
|
||||||
|
- **LIBOBS_LIB** (filepath) : location of the libobs.0.dylib file (usually
|
||||||
|
in /Applications/OBS.app/Contents/Resources/bin/libobs.0.dylib)
|
||||||
|
|
||||||
|
Assuming that you installed Qt via the regular Qt App way:
|
||||||
|
- **Qt5Core_DIR** (path) : Usually /Applications/Qt/5.10.1/clang_64/lib/cmake/Qt5Core
|
||||||
|
- **Qt5Widgets_DIR** (path) : Usually /Applications/Qt/5.10.1/clang_64/lib/cmake/Qt5Widgets
|
||||||
|
- **Qt5MacExtras_DIR** (path) : Usually /Applications/Qt/5.10.1/clang_64/lib/cmake/Qt5MacExtras
|
||||||
|
|
||||||
|
- **LIBOBS_FRONTEND_API_LIB** (filepath) : location of the libobs-frontend-api.0.dylib
|
||||||
|
file (usually in usually in /Applications/OBS.app/Contents/Resources/bin/libobs-frontend-api.0.dylib)
|
||||||
|
- **LIBOBS_FRONTEND_INCLUDE_DIR** (path) : location of the obs-frontend-api subfolder
|
||||||
|
in the source code of OBS Studio, located at [source_directory]/UI/obs-frontend-api.
|
||||||
|
|
||||||
|
Just keep hitting configure until all the vars are filled out. Then hit generate.
|
||||||
|
|
||||||
|
Open xcode (or a terminal, depending on the build type you chose), build and copy
|
||||||
|
the advanced-scene-switcher.so file to /Applications/OBS.app/Contents/Resources/obs-plugins/
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
107
external/FindLibObs.cmake
vendored
Normal file
107
external/FindLibObs.cmake
vendored
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
# This module can be copied and used by external plugins for OBS
|
||||||
|
#
|
||||||
|
# Once done these will be defined:
|
||||||
|
#
|
||||||
|
# LIBOBS_FOUND
|
||||||
|
# LIBOBS_INCLUDE_DIRS
|
||||||
|
# LIBOBS_LIBRARIES
|
||||||
|
|
||||||
|
find_package(PkgConfig QUIET)
|
||||||
|
if (PKG_CONFIG_FOUND)
|
||||||
|
pkg_check_modules(_OBS QUIET obs libobs)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||||
|
set(_lib_suffix 64)
|
||||||
|
else()
|
||||||
|
set(_lib_suffix 32)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(DEFINED CMAKE_BUILD_TYPE)
|
||||||
|
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||||
|
set(_build_type_base "debug")
|
||||||
|
else()
|
||||||
|
set(_build_type_base "release")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_path(LIBOBS_INCLUDE_DIR
|
||||||
|
NAMES obs.h
|
||||||
|
HINTS
|
||||||
|
ENV obsPath${_lib_suffix}
|
||||||
|
ENV obsPath
|
||||||
|
${obsPath}
|
||||||
|
PATHS
|
||||||
|
/usr/include /usr/local/include /opt/local/include /sw/include
|
||||||
|
PATH_SUFFIXES
|
||||||
|
libobs
|
||||||
|
)
|
||||||
|
|
||||||
|
function(find_obs_lib base_name repo_build_path lib_name)
|
||||||
|
string(TOUPPER "${base_name}" base_name_u)
|
||||||
|
|
||||||
|
if(DEFINED _build_type_base)
|
||||||
|
set(_build_type_${repo_build_path} "${_build_type_base}/${repo_build_path}")
|
||||||
|
set(_build_type_${repo_build_path}${_lib_suffix} "${_build_type_base}${_lib_suffix}/${repo_build_path}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_library(${base_name_u}_LIB
|
||||||
|
NAMES ${_${base_name_u}_LIBRARIES} ${lib_name} lib${lib_name}
|
||||||
|
HINTS
|
||||||
|
ENV obsPath${_lib_suffix}
|
||||||
|
ENV obsPath
|
||||||
|
${obsPath}
|
||||||
|
${_${base_name_u}_LIBRARY_DIRS}
|
||||||
|
PATHS
|
||||||
|
/usr/lib /usr/local/lib /opt/local/lib /sw/lib
|
||||||
|
PATH_SUFFIXES
|
||||||
|
lib${_lib_suffix} lib
|
||||||
|
libs${_lib_suffix} libs
|
||||||
|
bin${_lib_suffix} bin
|
||||||
|
../lib${_lib_suffix} ../lib
|
||||||
|
../libs${_lib_suffix} ../libs
|
||||||
|
../bin${_lib_suffix} ../bin
|
||||||
|
# base repo non-msvc-specific search paths
|
||||||
|
${_build_type_${repo_build_path}}
|
||||||
|
${_build_type_${repo_build_path}${_lib_suffix}}
|
||||||
|
build/${repo_build_path}
|
||||||
|
build${_lib_suffix}/${repo_build_path}
|
||||||
|
# base repo msvc-specific search paths on windows
|
||||||
|
build${_lib_suffix}/${repo_build_path}/Debug
|
||||||
|
build${_lib_suffix}/${repo_build_path}/RelWithDebInfo
|
||||||
|
build/${repo_build_path}/Debug
|
||||||
|
build/${repo_build_path}/RelWithDebInfo
|
||||||
|
)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
find_obs_lib(LIBOBS libobs obs)
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
find_obs_lib(W32_PTHREADS deps/w32-pthreads w32-pthreads)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
find_package_handle_standard_args(Libobs DEFAULT_MSG LIBOBS_LIB LIBOBS_INCLUDE_DIR)
|
||||||
|
mark_as_advanced(LIBOBS_INCLUDE_DIR LIBOBS_LIB)
|
||||||
|
|
||||||
|
if(LIBOBS_FOUND)
|
||||||
|
if(MSVC)
|
||||||
|
if (NOT DEFINED W32_PTHREADS_LIB)
|
||||||
|
message(FATAL_ERROR "Could not find the w32-pthreads library" )
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(W32_PTHREADS_INCLUDE_DIR ${LIBOBS_INCLUDE_DIR}/../deps/w32-pthreads)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(LIBOBS_INCLUDE_DIRS ${LIBOBS_INCLUDE_DIR} ${W32_PTHREADS_INCLUDE_DIR})
|
||||||
|
set(LIBOBS_LIBRARIES ${LIBOBS_LIB} ${W32_PTHREADS_LIB})
|
||||||
|
include(${LIBOBS_INCLUDE_DIR}/../cmake/external/ObsPluginHelpers.cmake)
|
||||||
|
|
||||||
|
# allows external plugins to easily use/share common dependencies that are often included with libobs (such as FFmpeg)
|
||||||
|
if(NOT DEFINED INCLUDED_LIBOBS_CMAKE_MODULES)
|
||||||
|
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${LIBOBS_INCLUDE_DIR}/../cmake/Modules/")
|
||||||
|
set(INCLUDED_LIBOBS_CMAKE_MODULES true)
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "Could not find the libobs library" )
|
||||||
|
endif()
|
||||||
163
external/ObsPluginHelpers.cmake
vendored
Normal file
163
external/ObsPluginHelpers.cmake
vendored
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
# Functions for generating external plugins
|
||||||
|
|
||||||
|
set(EXTERNAL_PLUGIN_OUTPUT_DIR "${CMAKE_BINARY_DIR}/rundir")
|
||||||
|
|
||||||
|
# Fix XCode includes to ignore warnings on system includes
|
||||||
|
function(target_include_directories_system _target)
|
||||||
|
if(XCODE)
|
||||||
|
foreach(_arg ${ARGN})
|
||||||
|
if("${_arg}" STREQUAL "PRIVATE" OR "${_arg}" STREQUAL "PUBLIC" OR "${_arg}" STREQUAL "INTERFACE")
|
||||||
|
set(_scope ${_arg})
|
||||||
|
else()
|
||||||
|
target_compile_options(${_target} ${_scope} -isystem${_arg})
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
else()
|
||||||
|
target_include_directories(${_target} SYSTEM ${_scope} ${ARGN})
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(install_external_plugin_data_internal target source_dir target_dir)
|
||||||
|
install(DIRECTORY ${source_dir}/
|
||||||
|
DESTINATION "${target}/${target_dir}"
|
||||||
|
USE_SOURCE_PERMISSIONS)
|
||||||
|
add_custom_command(TARGET ${target} POST_BUILD
|
||||||
|
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/${source_dir}" "${EXTERNAL_PLUGIN_OUTPUT_DIR}/$<CONFIGURATION>/${target}/${target_dir}"
|
||||||
|
VERBATIM)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Installs data
|
||||||
|
# 'target' is the destination target project being installed to
|
||||||
|
# 'data_loc' specifies the directory of the data
|
||||||
|
function(install_external_plugin_data target data_loc)
|
||||||
|
install_external_plugin_data_internal(${target} ${data_loc} "data")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Installs data in an architecture-specific data directory on windows/linux (data/32bit or data/64bit). Does not apply for mac.
|
||||||
|
# 'target' is the destination target project being installed to
|
||||||
|
# 'data_loc' specifies the directory of the data being installed
|
||||||
|
function(install_external_plugin_arch_data target data_loc)
|
||||||
|
if(APPLE)
|
||||||
|
set(_bit_suffix "")
|
||||||
|
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||||
|
set(_bit_suffix "/64bit")
|
||||||
|
else()
|
||||||
|
set(_bit_suffix "/32bit")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
install_external_plugin_data_internal(${target} ${data_loc} "data${_bit_suffix}")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Installs data in the target's bin directory
|
||||||
|
# 'target' is the destination target project being installed to
|
||||||
|
# 'data_loc' specifies the directory of the data being installed
|
||||||
|
function(install_external_plugin_data_to_bin target data_loc)
|
||||||
|
if(APPLE)
|
||||||
|
set(_bit_suffix "")
|
||||||
|
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||||
|
set(_bit_suffix "/64bit")
|
||||||
|
else()
|
||||||
|
set(_bit_suffix "/32bit")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
install_external_plugin_data_internal(${target} ${data_loc} "bin${_bit_suffix}")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Installs an additional binary to a target
|
||||||
|
# 'target' is the destination target project being installed to
|
||||||
|
# 'additional_target' specifies the additional binary
|
||||||
|
function(install_external_plugin_additional target additional_target)
|
||||||
|
if(APPLE)
|
||||||
|
set(_bit_suffix "")
|
||||||
|
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||||
|
set(_bit_suffix "64bit/")
|
||||||
|
else()
|
||||||
|
set(_bit_suffix "32bit/")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set_target_properties(${additional_target} PROPERTIES
|
||||||
|
PREFIX "")
|
||||||
|
|
||||||
|
install(TARGETS ${additional_target}
|
||||||
|
LIBRARY DESTINATION "bin"
|
||||||
|
RUNTIME DESTINATION "bin")
|
||||||
|
add_custom_command(TARGET ${additional_target} POST_BUILD
|
||||||
|
COMMAND "${CMAKE_COMMAND}" -E copy
|
||||||
|
"$<TARGET_FILE:${additional_target}>"
|
||||||
|
"${EXTERNAL_PLUGIN_OUTPUT_DIR}/$<CONFIGURATION>/${target}/bin/${_bit_suffix}$<TARGET_FILE_NAME:${additional_target}>"
|
||||||
|
VERBATIM)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Installs the binary of the target
|
||||||
|
# 'target' is the target project being installed
|
||||||
|
function(install_external_plugin target)
|
||||||
|
install_external_plugin_additional(${target} ${target})
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Installs the binary and data of the target
|
||||||
|
# 'target' is the destination target project being installed to
|
||||||
|
function(install_external_plugin_with_data target data_loc)
|
||||||
|
install_external_plugin(${target})
|
||||||
|
install_external_plugin_data(${target} ${data_loc})
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Installs an additional binary to the data of a target
|
||||||
|
# 'target' is the destination target project being installed to
|
||||||
|
# 'additional_target' specifies the additional binary
|
||||||
|
function(install_external_plugin_bin_to_data target additional_target)
|
||||||
|
install(TARGETS ${additional_target}
|
||||||
|
LIBRARY DESTINATION "data"
|
||||||
|
RUNTIME DESTINATION "data")
|
||||||
|
add_custom_command(TARGET ${additional_target} POST_BUILD
|
||||||
|
COMMAND "${CMAKE_COMMAND}" -E copy
|
||||||
|
"$<TARGET_FILE:${additional_target}>"
|
||||||
|
"${EXTERNAL_PLUGIN_OUTPUT_DIR}/$<CONFIGURATION>/${target}/data/$<TARGET_FILE_NAME:${additional_target}>"
|
||||||
|
VERBATIM)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Installs an additional binary in an architecture-specific data directory on windows/linux (data/32bit or data/64bit). Does not apply for mac.
|
||||||
|
# 'target' is the destination target project being installed to
|
||||||
|
# 'additional_target' specifies the additional binary
|
||||||
|
function(install_external_plugin_bin_to_arch_data target additional_target)
|
||||||
|
if(APPLE)
|
||||||
|
set(_bit_suffix "")
|
||||||
|
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||||
|
set(_bit_suffix "/64bit")
|
||||||
|
else()
|
||||||
|
set(_bit_suffix "/32bit")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
install(TARGETS ${additional_target}
|
||||||
|
LIBRARY DESTINATION "data${_bit_suffix}"
|
||||||
|
RUNTIME DESTINATION "data${_bit_suffix}")
|
||||||
|
add_custom_command(TARGET ${additional_target} POST_BUILD
|
||||||
|
COMMAND "${CMAKE_COMMAND}" -E copy
|
||||||
|
"$<TARGET_FILE:${additional_target}>"
|
||||||
|
"${EXTERNAL_PLUGIN_OUTPUT_DIR}/$<CONFIGURATION>/${target}/data${_bit_suffix}/$<TARGET_FILE_NAME:${additional_target}>"
|
||||||
|
VERBATIM)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Installs an additional file in an architecture-specific data directory on windows/linux (data/32bit or data/64bit). Does not apply for mac.
|
||||||
|
# 'target' is the destination target project being installed to
|
||||||
|
# 'additional_target' specifies the additional binary
|
||||||
|
function(install_external_plugin_data_file_to_arch_data target additional_target file_target)
|
||||||
|
if(APPLE)
|
||||||
|
set(_bit_suffix "")
|
||||||
|
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||||
|
set(_bit_suffix "/64bit")
|
||||||
|
else()
|
||||||
|
set(_bit_suffix "/32bit")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
get_filename_component(file_target_name ${file_target} NAME)
|
||||||
|
|
||||||
|
install(TARGETS ${additional_target}
|
||||||
|
LIBRARY DESTINATION "data${_bit_suffix}"
|
||||||
|
RUNTIME DESTINATION "data${_bit_suffix}")
|
||||||
|
add_custom_command(TARGET ${additional_target} POST_BUILD
|
||||||
|
COMMAND "${CMAKE_COMMAND}" -E copy
|
||||||
|
"${file_target}"
|
||||||
|
"${EXTERNAL_PLUGIN_OUTPUT_DIR}/$<CONFIGURATION>/${target}/data${_bit_suffix}/${file_target_name}"
|
||||||
|
VERBATIM)
|
||||||
|
endfunction()
|
||||||
113
file-switch.cpp
113
file-switch.cpp
@@ -1,113 +0,0 @@
|
|||||||
#include <QFileDialog>
|
|
||||||
#include <QTextStream>
|
|
||||||
#include <obs.hpp>
|
|
||||||
#include "advanced-scene-switcher.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void SceneSwitcher::on_browseButton_clicked()
|
|
||||||
{
|
|
||||||
QString directory = QFileDialog::getOpenFileName(
|
|
||||||
this, tr("Select a file to write to ..."), QDir::currentPath(), tr("Text files (*.txt)"));
|
|
||||||
if (!directory.isEmpty())
|
|
||||||
ui->writePathLineEdit->setText(directory);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_readFileCheckBox_stateChanged(int state)
|
|
||||||
{
|
|
||||||
if (loading)
|
|
||||||
return;
|
|
||||||
|
|
||||||
lock_guard<mutex> lock(switcher->m);
|
|
||||||
if (!state)
|
|
||||||
{
|
|
||||||
ui->browseButton_2->setDisabled(true);
|
|
||||||
ui->readPathLineEdit->setDisabled(true);
|
|
||||||
switcher->fileIO.readEnabled = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ui->browseButton_2->setDisabled(false);
|
|
||||||
ui->readPathLineEdit->setDisabled(false);
|
|
||||||
switcher->fileIO.readEnabled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_readPathLineEdit_textChanged(const QString& text)
|
|
||||||
{
|
|
||||||
if (loading)
|
|
||||||
return;
|
|
||||||
|
|
||||||
lock_guard<mutex> lock(switcher->m);
|
|
||||||
if (text.isEmpty())
|
|
||||||
{
|
|
||||||
switcher->fileIO.readEnabled = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
switcher->fileIO.readEnabled = true;
|
|
||||||
switcher->fileIO.readPath = text.toUtf8().constData();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_writePathLineEdit_textChanged(const QString& text)
|
|
||||||
{
|
|
||||||
if (loading)
|
|
||||||
return;
|
|
||||||
|
|
||||||
lock_guard<mutex> lock(switcher->m);
|
|
||||||
if (text.isEmpty())
|
|
||||||
{
|
|
||||||
switcher->fileIO.writeEnabled = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
switcher->fileIO.writeEnabled = true;
|
|
||||||
switcher->fileIO.writePath = text.toUtf8().constData();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneSwitcher::on_browseButton_2_clicked()
|
|
||||||
{
|
|
||||||
QString directory = QFileDialog::getOpenFileName(
|
|
||||||
this, tr("Select a file to read from ..."), QDir::currentPath(), tr("Text files (*.txt)"));
|
|
||||||
if (!directory.isEmpty())
|
|
||||||
ui->readPathLineEdit->setText(directory);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SwitcherData::writeSceneInfoToFile()
|
|
||||||
{
|
|
||||||
obs_source_t* currentSource = obs_frontend_get_current_scene();
|
|
||||||
|
|
||||||
QFile file(QString::fromStdString(fileIO.writePath));
|
|
||||||
if (file.open(QIODevice::WriteOnly))
|
|
||||||
{
|
|
||||||
const char* msg = obs_source_get_name(currentSource);
|
|
||||||
file.write(msg, qstrlen(msg));
|
|
||||||
file.close();
|
|
||||||
}
|
|
||||||
obs_source_release(currentSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
obs_weak_source_t* getNextTransition(obs_weak_source_t* scene1, obs_weak_source_t* scene2);
|
|
||||||
|
|
||||||
void SwitcherData::checkSwitchInfoFromFile(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
|
|
||||||
{
|
|
||||||
if (!fileIO.readEnabled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
QFile file(QString::fromStdString(fileIO.readPath));
|
|
||||||
if (file.open(QIODevice::ReadOnly))
|
|
||||||
{
|
|
||||||
QTextStream in(&file);
|
|
||||||
QString sceneStr = in.readLine();
|
|
||||||
obs_source_t* sceneRead = obs_get_source_by_name(sceneStr.toUtf8().constData());
|
|
||||||
if (sceneRead){
|
|
||||||
obs_weak_source_t* sceneReadWs = obs_source_get_weak_source(sceneRead);
|
|
||||||
|
|
||||||
match = true;
|
|
||||||
scene = sceneReadWs;
|
|
||||||
transition = nullptr;
|
|
||||||
|
|
||||||
obs_weak_source_release(sceneReadWs);
|
|
||||||
obs_source_release(sceneRead);
|
|
||||||
}
|
|
||||||
file.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,11 +7,11 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>981</width>
|
<width>981</width>
|
||||||
<height>403</height>
|
<height>457</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>SceneSwitcher</string>
|
<string>Advanced Scene Switcher</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item>
|
<item>
|
||||||
@@ -25,101 +25,11 @@
|
|||||||
</attribute>
|
</attribute>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_31">
|
<widget class="Line" name="line_6">
|
||||||
<item>
|
<property name="orientation">
|
||||||
<spacer name="horizontalSpacer_29">
|
<enum>Qt::Horizontal</enum>
|
||||||
<property name="orientation">
|
</property>
|
||||||
<enum>Qt::Horizontal</enum>
|
</widget>
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="description">
|
|
||||||
<property name="text">
|
|
||||||
<string>Order the different switching methods in order of their priority (with the highest priority being at the top):</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer_30">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QListWidget" name="priorityList"/>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_32">
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="priorityUp">
|
|
||||||
<property name="maximumSize">
|
|
||||||
<size>
|
|
||||||
<width>22</width>
|
|
||||||
<height>22</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="icon">
|
|
||||||
<iconset>
|
|
||||||
<normaloff>../../../forms/images/up.png</normaloff>../../../forms/images/up.png</iconset>
|
|
||||||
</property>
|
|
||||||
<property name="flat">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="themeID" stdset="0">
|
|
||||||
<string notr="true">upArrowIconSmall</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="priorityDown">
|
|
||||||
<property name="maximumSize">
|
|
||||||
<size>
|
|
||||||
<width>22</width>
|
|
||||||
<height>22</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="icon">
|
|
||||||
<iconset>
|
|
||||||
<normaloff>../../../forms/images/down.png</normaloff>../../../forms/images/down.png</iconset>
|
|
||||||
</property>
|
|
||||||
<property name="flat">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="themeID" stdset="0">
|
|
||||||
<string notr="true">downArrowIconSmall</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer_31">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QFormLayout" name="formLayout">
|
<layout class="QFormLayout" name="formLayout">
|
||||||
@@ -205,6 +115,13 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="noMatchRandomSwitch">
|
||||||
|
<property name="text">
|
||||||
|
<string>Switch to any Scene on Random Tab</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="1" column="0">
|
||||||
@@ -288,6 +205,97 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line_8">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_31">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="description">
|
||||||
|
<property name="text">
|
||||||
|
<string>Order the different switching methods in order of their priority (with the highest priority being at the top):</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_30">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="priorityList"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_32">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="priorityUp">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>22</width>
|
||||||
|
<height>22</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset>
|
||||||
|
<normaloff>../../../forms/images/up.png</normaloff>../../../forms/images/up.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="themeID" stdset="0">
|
||||||
|
<string notr="true">upArrowIconSmall</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="priorityDown">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>22</width>
|
||||||
|
<height>22</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset>
|
||||||
|
<normaloff>../../../forms/images/down.png</normaloff>../../../forms/images/down.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="themeID" stdset="0">
|
||||||
|
<string notr="true">downArrowIconSmall</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_31">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_33">
|
<layout class="QHBoxLayout" name="horizontalLayout_33">
|
||||||
<item>
|
<item>
|
||||||
@@ -328,6 +336,20 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line_7">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_13">
|
||||||
|
<property name="text">
|
||||||
|
<string>(You can set a Hotkey to start and stop the scene switcher under Settings / Hotkeys / Toggle Start Stop for the Advanced Scene Switcher)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="close">
|
<widget class="QPushButton" name="close">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@@ -460,6 +482,13 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line_5">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_9">
|
<layout class="QHBoxLayout" name="horizontalLayout_9">
|
||||||
<item>
|
<item>
|
||||||
@@ -575,6 +604,20 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line_9">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_47">
|
||||||
|
<property name="text">
|
||||||
|
<string>(If you want to add OBS itself as a window title use "OBS" - If you want to add ALT + TAB add "Task Switching")</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QWidget" name="screenRegionTab">
|
<widget class="QWidget" name="screenRegionTab">
|
||||||
@@ -897,18 +940,12 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QSpinBox" name="sceneRoundTripSpinBox">
|
<widget class="QDoubleSpinBox" name="sceneRoundTripSpinBox">
|
||||||
<property name="suffix">
|
<property name="suffix">
|
||||||
<string>s</string>
|
<string>s</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="prefix">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="minimum">
|
|
||||||
<number>1</number>
|
|
||||||
</property>
|
|
||||||
<property name="maximum">
|
<property name="maximum">
|
||||||
<number>1000000</number>
|
<double>1000000.000000000000000</double>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -1512,6 +1549,13 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line_4">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_34">
|
<layout class="QHBoxLayout" name="horizontalLayout_34">
|
||||||
<item>
|
<item>
|
||||||
@@ -1783,6 +1827,13 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line_3">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="transitionWarning">
|
<widget class="QLabel" name="transitionWarning">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@@ -1911,6 +1962,149 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QWidget" name="randomTab">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Random</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_8">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_42">
|
||||||
|
<property name="text">
|
||||||
|
<string>If no switch condition is met switch to </string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="randomScenes">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>100</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_43">
|
||||||
|
<property name="text">
|
||||||
|
<string>using the</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="randomTransitions"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_41">
|
||||||
|
<property name="text">
|
||||||
|
<string>transition for a duration of</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDoubleSpinBox" name="randomSpinBox">
|
||||||
|
<property name="suffix">
|
||||||
|
<string>s</string>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<double>999999999.990000009536743</double>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_14">
|
||||||
|
<property name="text">
|
||||||
|
<string>or any of the options below:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_36">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="randomScenesList">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="sortingEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="randomAdd">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>22</width>
|
||||||
|
<height>22</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="themeID" stdset="0">
|
||||||
|
<string notr="true">addIconSmall</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="randomRemove">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>22</width>
|
||||||
|
<height>22</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="themeID" stdset="0">
|
||||||
|
<string notr="true">removeIconSmall</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_37">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
<widget class="QWidget" name="fileTab">
|
<widget class="QWidget" name="fileTab">
|
||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
<string> Write To File / Read From File </string>
|
<string> Write To File / Read From File </string>
|
||||||
@@ -1938,51 +2132,412 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_10">
|
<widget class="Line" name="line_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_16">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_16">
|
<widget class="QCheckBox" name="readFileCheckBox">
|
||||||
<item>
|
<property name="text">
|
||||||
<widget class="QCheckBox" name="readFileCheckBox">
|
<string>Enable switching of scenes based on file input</string>
|
||||||
<property name="text">
|
</property>
|
||||||
<string>Enable switching of scenes based on file input</string>
|
</widget>
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer_12">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_15">
|
<spacer name="horizontalSpacer_12">
|
||||||
<item>
|
<property name="orientation">
|
||||||
<widget class="QLabel" name="label_16">
|
<enum>Qt::Horizontal</enum>
|
||||||
<property name="text">
|
</property>
|
||||||
<string>Read scene to be switched to from this file:</string>
|
<property name="sizeHint" stdset="0">
|
||||||
</property>
|
<size>
|
||||||
</widget>
|
<width>40</width>
|
||||||
</item>
|
<height>20</height>
|
||||||
<item>
|
</size>
|
||||||
<widget class="QLineEdit" name="readPathLineEdit"/>
|
</property>
|
||||||
</item>
|
</spacer>
|
||||||
<item>
|
</item>
|
||||||
<widget class="QPushButton" name="browseButton_2">
|
</layout>
|
||||||
<property name="text">
|
</item>
|
||||||
<string>Browse</string>
|
<item>
|
||||||
</property>
|
<layout class="QHBoxLayout" name="horizontalLayout_15">
|
||||||
</widget>
|
<item>
|
||||||
</item>
|
<widget class="QLabel" name="label_16">
|
||||||
</layout>
|
<property name="text">
|
||||||
|
<string>Read scene name to be switched to from this file:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="readPathLineEdit"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="browseButton_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Browse</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_39">
|
||||||
|
<property name="text">
|
||||||
|
<string>Switch scene based on file contents:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_36">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_44">
|
||||||
|
<property name="text">
|
||||||
|
<string>If the file</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="filePathLineEdit"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="browseButton_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>Browse</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_40">
|
||||||
|
<property name="text">
|
||||||
|
<string>contains:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPlainTextEdit" name="fileTextEdit"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_37">
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="fileContentRegExCheckBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>Use regular expression (pattern matching)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="fileContentTimeCheckBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>Only check contents if modification date changed</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_11">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_38">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_45">
|
||||||
|
<property name="text">
|
||||||
|
<string>switch to</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="fileScenes">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>100</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_46">
|
||||||
|
<property name="text">
|
||||||
|
<string>using</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="fileTransitions"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="fileScenesList">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="sortingEnabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_35">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="fileAdd">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>22</width>
|
||||||
|
<height>22</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="themeID" stdset="0">
|
||||||
|
<string notr="true">addIconSmall</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="fileRemove">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>22</width>
|
||||||
|
<height>22</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="themeID" stdset="0">
|
||||||
|
<string notr="true">removeIconSmall</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_38">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="mediaTab">
|
||||||
|
<attribute name="title">
|
||||||
|
<string> Media </string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_11">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_39">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_48">
|
||||||
|
<property name="text">
|
||||||
|
<string>When</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="mediaSources"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_49">
|
||||||
|
<property name="text">
|
||||||
|
<string>state is</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="mediaStates"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_50">
|
||||||
|
<property name="text">
|
||||||
|
<string>and</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="mediaTimeRestrictions"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="mediaTime">
|
||||||
|
<property name="suffix">
|
||||||
|
<string notr="true">ms</string>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>00</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>1000000</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_51">
|
||||||
|
<property name="text">
|
||||||
|
<string>switch to</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="mediaScenes">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>100</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_52">
|
||||||
|
<property name="text">
|
||||||
|
<string>using the</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="mediaTransitions"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_53">
|
||||||
|
<property name="text">
|
||||||
|
<string>transition</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_29">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="mediaSwitches">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="sortingEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_40">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>4</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="mediaAdd">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>22</width>
|
||||||
|
<height>22</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="themeID" stdset="0">
|
||||||
|
<string notr="true">addIconSmall</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="mediaRemove">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>22</width>
|
||||||
|
<height>22</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="themeID" stdset="0">
|
||||||
|
<string notr="true">removeIconSmall</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_35">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_54">
|
||||||
|
<property name="text">
|
||||||
|
<string>Implemented by Exeldro</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
|||||||
72
hotkey.cpp
72
hotkey.cpp
@@ -1,72 +0,0 @@
|
|||||||
#include <obs-module.h>
|
|
||||||
#include "advanced-scene-switcher.hpp"
|
|
||||||
|
|
||||||
void startStopHotkeyFunc(void* data, obs_hotkey_id id, obs_hotkey_t* hotkey, bool pressed)
|
|
||||||
{
|
|
||||||
UNUSED_PARAMETER(data);
|
|
||||||
UNUSED_PARAMETER(hotkey);
|
|
||||||
|
|
||||||
if (pressed)
|
|
||||||
{
|
|
||||||
if (switcher->th.joinable())
|
|
||||||
switcher->Stop();
|
|
||||||
else
|
|
||||||
switcher->Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
obs_data_array* hotkeyData = obs_hotkey_save(id);
|
|
||||||
|
|
||||||
if (hotkeyData != NULL)
|
|
||||||
{
|
|
||||||
char* path = obs_module_config_path("");
|
|
||||||
ofstream file;
|
|
||||||
file.open(string(path).append("hotkey.txt"), ofstream::trunc);
|
|
||||||
if (file.is_open())
|
|
||||||
{
|
|
||||||
size_t num = obs_data_array_count(hotkeyData);
|
|
||||||
for (size_t i = 0; i < num; i++)
|
|
||||||
{
|
|
||||||
obs_data_t* data = obs_data_array_item(hotkeyData, i);
|
|
||||||
string temp = obs_data_get_json(data);
|
|
||||||
obs_data_release(data);
|
|
||||||
file << temp;
|
|
||||||
}
|
|
||||||
file.close();
|
|
||||||
}
|
|
||||||
bfree(path);
|
|
||||||
}
|
|
||||||
obs_data_array_release(hotkeyData);
|
|
||||||
}
|
|
||||||
|
|
||||||
string loadConfigFile(string filename)
|
|
||||||
{
|
|
||||||
ifstream settingsFile;
|
|
||||||
char* path = obs_module_config_path("");
|
|
||||||
string value;
|
|
||||||
|
|
||||||
settingsFile.open(string(path).append(filename));
|
|
||||||
if (settingsFile.is_open())
|
|
||||||
{
|
|
||||||
settingsFile.seekg(0, ios::end);
|
|
||||||
value.reserve(settingsFile.tellg());
|
|
||||||
settingsFile.seekg(0, ios::beg);
|
|
||||||
value.assign((istreambuf_iterator<char>(settingsFile)), istreambuf_iterator<char>());
|
|
||||||
settingsFile.close();
|
|
||||||
}
|
|
||||||
bfree(path);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void loadKeybinding(obs_hotkey_id hotkeyId)
|
|
||||||
{
|
|
||||||
string bindings = loadConfigFile("hotkey.txt");
|
|
||||||
if (!bindings.empty())
|
|
||||||
{
|
|
||||||
obs_data_array_t* hotkeyData = obs_data_array_create();
|
|
||||||
obs_data_t* data = obs_data_create_from_json(bindings.c_str());
|
|
||||||
obs_data_array_insert(hotkeyData, 0, data);
|
|
||||||
obs_data_release(data);
|
|
||||||
obs_hotkey_load(hotkeyId, hotkeyData);
|
|
||||||
obs_data_array_release(hotkeyData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
#include <obs-module.h>
|
#include <obs-module.h>
|
||||||
|
|
||||||
OBS_DECLARE_MODULE()
|
OBS_DECLARE_MODULE()
|
||||||
OBS_MODULE_USE_DEFAULT_LOCALE("frontend-tools", "en-US")
|
|
||||||
|
|
||||||
void InitSceneSwitcher();
|
void InitSceneSwitcher();
|
||||||
void FreeSceneSwitcher();
|
void FreeSceneSwitcher();
|
||||||
1529
src/advanced-scene-switcher.cpp
Normal file
1529
src/advanced-scene-switcher.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
|||||||
#include "advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
|
||||||
int SceneSwitcher::executableFindByData(const QString& exe)
|
int SceneSwitcher::executableFindByData(const QString& exe)
|
||||||
{
|
{
|
||||||
254
src/file-switch.cpp
Normal file
254
src/file-switch.cpp
Normal file
@@ -0,0 +1,254 @@
|
|||||||
|
#include <QFileDialog>
|
||||||
|
#include <QTextStream>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <obs.hpp>
|
||||||
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void SceneSwitcher::on_browseButton_clicked()
|
||||||
|
{
|
||||||
|
QString path = QFileDialog::getOpenFileName(
|
||||||
|
this, tr("Select a file to write to ..."), QDir::currentPath(), tr("Text files (*.txt)"));
|
||||||
|
if (!path.isEmpty())
|
||||||
|
ui->writePathLineEdit->setText(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneSwitcher::on_readFileCheckBox_stateChanged(int state)
|
||||||
|
{
|
||||||
|
if (loading)
|
||||||
|
return;
|
||||||
|
|
||||||
|
lock_guard<mutex> lock(switcher->m);
|
||||||
|
if (!state)
|
||||||
|
{
|
||||||
|
ui->browseButton_2->setDisabled(true);
|
||||||
|
ui->readPathLineEdit->setDisabled(true);
|
||||||
|
switcher->fileIO.readEnabled = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->browseButton_2->setDisabled(false);
|
||||||
|
ui->readPathLineEdit->setDisabled(false);
|
||||||
|
switcher->fileIO.readEnabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneSwitcher::on_readPathLineEdit_textChanged(const QString& text)
|
||||||
|
{
|
||||||
|
if (loading)
|
||||||
|
return;
|
||||||
|
|
||||||
|
lock_guard<mutex> lock(switcher->m);
|
||||||
|
if (text.isEmpty())
|
||||||
|
{
|
||||||
|
switcher->fileIO.readEnabled = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switcher->fileIO.readEnabled = true;
|
||||||
|
switcher->fileIO.readPath = text.toUtf8().constData();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneSwitcher::on_writePathLineEdit_textChanged(const QString& text)
|
||||||
|
{
|
||||||
|
if (loading)
|
||||||
|
return;
|
||||||
|
|
||||||
|
lock_guard<mutex> lock(switcher->m);
|
||||||
|
if (text.isEmpty())
|
||||||
|
{
|
||||||
|
switcher->fileIO.writeEnabled = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switcher->fileIO.writeEnabled = true;
|
||||||
|
switcher->fileIO.writePath = text.toUtf8().constData();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneSwitcher::on_browseButton_2_clicked()
|
||||||
|
{
|
||||||
|
QString path = QFileDialog::getOpenFileName(
|
||||||
|
this, tr("Select a file to read from ..."), QDir::currentPath(), tr("Any files (*.*)"));
|
||||||
|
if (!path.isEmpty())
|
||||||
|
ui->readPathLineEdit->setText(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitcherData::writeSceneInfoToFile()
|
||||||
|
{
|
||||||
|
if (!fileIO.writeEnabled || fileIO.writePath.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
obs_source_t* currentSource = obs_frontend_get_current_scene();
|
||||||
|
|
||||||
|
QFile file(QString::fromStdString(fileIO.writePath));
|
||||||
|
if (file.open(QIODevice::WriteOnly))
|
||||||
|
{
|
||||||
|
const char* msg = obs_source_get_name(currentSource);
|
||||||
|
file.write(msg, qstrlen(msg));
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
obs_source_release(currentSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitcherData::checkSwitchInfoFromFile(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
|
||||||
|
{
|
||||||
|
if (!fileIO.readEnabled || fileIO.readPath.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
QFile file(QString::fromStdString(fileIO.readPath));
|
||||||
|
if (file.open(QIODevice::ReadOnly))
|
||||||
|
{
|
||||||
|
QTextStream in(&file);
|
||||||
|
QString sceneStr = in.readLine();
|
||||||
|
obs_source_t* sceneRead = obs_get_source_by_name(sceneStr.toUtf8().constData());
|
||||||
|
if (sceneRead){
|
||||||
|
obs_weak_source_t* sceneReadWs = obs_source_get_weak_source(sceneRead);
|
||||||
|
|
||||||
|
match = true;
|
||||||
|
scene = sceneReadWs;
|
||||||
|
transition = nullptr;
|
||||||
|
|
||||||
|
obs_weak_source_release(sceneReadWs);
|
||||||
|
obs_source_release(sceneRead);
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitcherData::checkFileContent(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
|
||||||
|
{
|
||||||
|
for (FileSwitch& s : fileSwitches)
|
||||||
|
{
|
||||||
|
bool equal = false;
|
||||||
|
QString t = QString::fromStdString(s.text);
|
||||||
|
QFile file(QString::fromStdString(s.file));
|
||||||
|
if (!file.open(QIODevice::ReadOnly))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (s.useTime)
|
||||||
|
{
|
||||||
|
QDateTime newLastMod = QFileInfo(file).lastModified();
|
||||||
|
if (s.lastMod == newLastMod)
|
||||||
|
continue;
|
||||||
|
s.lastMod = newLastMod;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s.useRegex)
|
||||||
|
{
|
||||||
|
QTextStream in(&file);
|
||||||
|
QRegExp rx(t);
|
||||||
|
equal = rx.exactMatch(in.readAll());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*Im using QTextStream here so the conversion between different lineendings is done by QT.
|
||||||
|
*QT itself uses only the linefeed internally so the input by the user is always using that,
|
||||||
|
*but the files selected by the user might use different line endings.
|
||||||
|
*If you are reading this and know of a cleaner way to do this, please let me know :)
|
||||||
|
*/
|
||||||
|
QTextStream in(&file);
|
||||||
|
QTextStream text(&t);
|
||||||
|
while (!in.atEnd() && !text.atEnd())
|
||||||
|
{
|
||||||
|
QString fileLine = in.readLine();
|
||||||
|
QString textLine = text.readLine();
|
||||||
|
if (QString::compare(fileLine, textLine, Qt::CaseSensitive) != 0)
|
||||||
|
{
|
||||||
|
equal = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
equal = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
if (equal)
|
||||||
|
{
|
||||||
|
scene = s.scene;
|
||||||
|
transition = s.transition;
|
||||||
|
match = true;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneSwitcher::on_browseButton_3_clicked()
|
||||||
|
{
|
||||||
|
QString path = QFileDialog::getOpenFileName(
|
||||||
|
this, tr("Select a file to read from ..."), QDir::currentPath(), tr("Any files (*.*)"));
|
||||||
|
if (!path.isEmpty())
|
||||||
|
ui->filePathLineEdit->setText(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneSwitcher::on_fileAdd_clicked()
|
||||||
|
{
|
||||||
|
QString sceneName = ui->fileScenes->currentText();
|
||||||
|
QString transitionName = ui->fileTransitions->currentText();
|
||||||
|
QString fileName = ui->filePathLineEdit->text();
|
||||||
|
QString text = ui->fileTextEdit->toPlainText();
|
||||||
|
bool useRegex = ui->fileContentRegExCheckBox->isChecked();
|
||||||
|
bool useTime = ui->fileContentTimeCheckBox->isChecked();
|
||||||
|
|
||||||
|
if (sceneName.isEmpty() || transitionName.isEmpty() || fileName.isEmpty() || text.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
OBSWeakSource source = GetWeakSourceByQString(sceneName);
|
||||||
|
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
|
||||||
|
|
||||||
|
QString switchText = MakeFileSwitchName(sceneName, transitionName, fileName, text, useRegex, useTime);
|
||||||
|
QVariant v = QVariant::fromValue(switchText);
|
||||||
|
|
||||||
|
|
||||||
|
QListWidgetItem* item = new QListWidgetItem(switchText, ui->fileScenesList);
|
||||||
|
item->setData(Qt::UserRole, v);
|
||||||
|
|
||||||
|
lock_guard<mutex> lock(switcher->m);
|
||||||
|
switcher->fileSwitches.emplace_back(
|
||||||
|
source, transition, fileName.toUtf8().constData(), text.toUtf8().constData(), useRegex, useTime);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneSwitcher::on_fileRemove_clicked()
|
||||||
|
{
|
||||||
|
QListWidgetItem* item = ui->fileScenesList->currentItem();
|
||||||
|
if (!item)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int idx = ui->fileScenesList->currentRow();
|
||||||
|
if (idx == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
{
|
||||||
|
lock_guard<mutex> lock(switcher->m);
|
||||||
|
|
||||||
|
auto& switches = switcher->fileSwitches;
|
||||||
|
switches.erase(switches.begin() + idx);
|
||||||
|
}
|
||||||
|
qDeleteAll(ui->fileScenesList->selectedItems());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneSwitcher::on_fileScenesList_currentRowChanged(int idx)
|
||||||
|
{
|
||||||
|
if (loading)
|
||||||
|
return;
|
||||||
|
if (idx == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
lock_guard<mutex> lock(switcher->m);
|
||||||
|
|
||||||
|
if (switcher->fileSwitches.size() <= idx)
|
||||||
|
return;
|
||||||
|
FileSwitch s = switcher->fileSwitches[idx];
|
||||||
|
|
||||||
|
string sceneName = GetWeakSourceName(s.scene);
|
||||||
|
string transitionName = GetWeakSourceName(s.transition);
|
||||||
|
|
||||||
|
ui->fileScenes->setCurrentText(sceneName.c_str());
|
||||||
|
ui->fileTransitions->setCurrentText(transitionName.c_str());
|
||||||
|
ui->fileTextEdit->setPlainText(s.text.c_str());
|
||||||
|
ui->filePathLineEdit->setText(s.file.c_str());
|
||||||
|
ui->fileContentRegExCheckBox->setChecked(s.useRegex);
|
||||||
|
ui->fileContentTimeCheckBox->setChecked(s.useTime);
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
#include <obs-module.h>
|
#include <obs-module.h>
|
||||||
|
|
||||||
void SceneSwitcher::on_close_clicked()
|
void SceneSwitcher::on_close_clicked()
|
||||||
@@ -32,7 +32,8 @@ void SceneSwitcher::on_noMatchDontSwitch_clicked()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
lock_guard<mutex> lock(switcher->m);
|
lock_guard<mutex> lock(switcher->m);
|
||||||
switcher->switchIfNotMatching = false;
|
switcher->switchIfNotMatching = NO_SWITCH;
|
||||||
|
ui->noMatchSwitchScene->setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_noMatchSwitch_clicked()
|
void SceneSwitcher::on_noMatchSwitch_clicked()
|
||||||
@@ -41,10 +42,21 @@ void SceneSwitcher::on_noMatchSwitch_clicked()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
lock_guard<mutex> lock(switcher->m);
|
lock_guard<mutex> lock(switcher->m);
|
||||||
switcher->switchIfNotMatching = true;
|
switcher->switchIfNotMatching = SWITCH;
|
||||||
|
ui->noMatchSwitchScene->setEnabled(true);
|
||||||
UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText());
|
UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SceneSwitcher::on_noMatchRandomSwitch_clicked()
|
||||||
|
{
|
||||||
|
if (loading)
|
||||||
|
return;
|
||||||
|
|
||||||
|
lock_guard<mutex> lock(switcher->m);
|
||||||
|
switcher->switchIfNotMatching = RANDOM_SWITCH;
|
||||||
|
ui->noMatchSwitchScene->setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_noMatchSwitchScene_currentTextChanged(const QString& text)
|
void SceneSwitcher::on_noMatchSwitchScene_currentTextChanged(const QString& text)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading)
|
||||||
@@ -65,14 +77,14 @@ void SceneSwitcher::on_checkInterval_valueChanged(int value)
|
|||||||
|
|
||||||
void SceneSwitcher::SetStarted()
|
void SceneSwitcher::SetStarted()
|
||||||
{
|
{
|
||||||
ui->toggleStartButton->setText(obs_module_text("Stop"));
|
ui->toggleStartButton->setText("Stop");
|
||||||
ui->pluginRunningText->setText(obs_module_text("Active"));
|
ui->pluginRunningText->setText("Active");
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::SetStopped()
|
void SceneSwitcher::SetStopped()
|
||||||
{
|
{
|
||||||
ui->toggleStartButton->setText(obs_module_text("Start"));
|
ui->toggleStartButton->setText("Start");
|
||||||
ui->pluginRunningText->setText(obs_module_text("Inactive"));
|
ui->pluginRunningText->setText("Inactive");
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_toggleStartButton_clicked()
|
void SceneSwitcher::on_toggleStartButton_clicked()
|
||||||
@@ -4,14 +4,18 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#ifdef BUILD_OUT_OF_TREE
|
||||||
|
#include "../../forms/ui_advanced-scene-switcher.h"
|
||||||
|
#else
|
||||||
#include "ui_advanced-scene-switcher.h"
|
#include "ui_advanced-scene-switcher.h"
|
||||||
|
#endif
|
||||||
#include "switcher-data-structs.hpp"
|
#include "switcher-data-structs.hpp"
|
||||||
|
|
||||||
struct obs_weak_source;
|
|
||||||
typedef struct obs_weak_source obs_weak_source_t;
|
|
||||||
|
|
||||||
class QCloseEvent;
|
class QCloseEvent;
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Advanced Scene Switcher window
|
||||||
|
*******************************************************************************/
|
||||||
class SceneSwitcher : public QDialog {
|
class SceneSwitcher : public QDialog {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@@ -32,15 +36,17 @@ public:
|
|||||||
int PauseWindowsFindByData(const QString &window);
|
int PauseWindowsFindByData(const QString &window);
|
||||||
int IgnoreWindowsFindByData(const QString &window);
|
int IgnoreWindowsFindByData(const QString &window);
|
||||||
int SceneRoundTripFindByData(const QString &scene1);
|
int SceneRoundTripFindByData(const QString &scene1);
|
||||||
int SceneTransitionsFindByData(const QString &scene1, const QString &scene2);
|
int SceneTransitionsFindByData(const QString &scene1,
|
||||||
|
const QString &scene2);
|
||||||
int DefaultTransitionsFindByData(const QString &scene);
|
int DefaultTransitionsFindByData(const QString &scene);
|
||||||
int executableFindByData(const QString &exe);
|
int executableFindByData(const QString &exe);
|
||||||
int IgnoreIdleWindowsFindByData(const QString& window);
|
int IgnoreIdleWindowsFindByData(const QString &window);
|
||||||
|
int randomFindByData(const QString &scene);
|
||||||
|
|
||||||
void UpdateNonMatchingScene(const QString &name);
|
void UpdateNonMatchingScene(const QString &name);
|
||||||
void UpdateAutoStopScene(const QString &name);
|
void UpdateAutoStopScene(const QString &name);
|
||||||
void UpdateIdleDataTransition(const QString& name);
|
void UpdateIdleDataTransition(const QString &name);
|
||||||
void UpdateIdleDataScene(const QString& name);
|
void UpdateIdleDataScene(const QString &name);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void on_switches_currentRowChanged(int idx);
|
void on_switches_currentRowChanged(int idx);
|
||||||
@@ -48,6 +54,7 @@ public slots:
|
|||||||
void on_remove_clicked();
|
void on_remove_clicked();
|
||||||
void on_noMatchDontSwitch_clicked();
|
void on_noMatchDontSwitch_clicked();
|
||||||
void on_noMatchSwitch_clicked();
|
void on_noMatchSwitch_clicked();
|
||||||
|
void on_noMatchRandomSwitch_clicked();
|
||||||
void on_startAtLaunch_toggled(bool value);
|
void on_startAtLaunch_toggled(bool value);
|
||||||
void on_noMatchSwitchScene_currentTextChanged(const QString &text);
|
void on_noMatchSwitchScene_currentTextChanged(const QString &text);
|
||||||
void on_checkInterval_valueChanged(int value);
|
void on_checkInterval_valueChanged(int value);
|
||||||
@@ -87,8 +94,8 @@ public slots:
|
|||||||
|
|
||||||
void on_browseButton_clicked();
|
void on_browseButton_clicked();
|
||||||
void on_readFileCheckBox_stateChanged(int state);
|
void on_readFileCheckBox_stateChanged(int state);
|
||||||
void on_readPathLineEdit_textChanged(const QString & text);
|
void on_readPathLineEdit_textChanged(const QString &text);
|
||||||
void on_writePathLineEdit_textChanged(const QString & text);
|
void on_writePathLineEdit_textChanged(const QString &text);
|
||||||
void on_browseButton_2_clicked();
|
void on_browseButton_2_clicked();
|
||||||
|
|
||||||
void on_executableAdd_clicked();
|
void on_executableAdd_clicked();
|
||||||
@@ -96,13 +103,25 @@ public slots:
|
|||||||
void on_executables_currentRowChanged(int idx);
|
void on_executables_currentRowChanged(int idx);
|
||||||
|
|
||||||
void on_idleCheckBox_stateChanged(int state);
|
void on_idleCheckBox_stateChanged(int state);
|
||||||
void on_idleTransitions_currentTextChanged(const QString& text);
|
void on_idleTransitions_currentTextChanged(const QString &text);
|
||||||
void on_idleScenes_currentTextChanged(const QString& text);
|
void on_idleScenes_currentTextChanged(const QString &text);
|
||||||
void on_idleSpinBox_valueChanged(int i);
|
void on_idleSpinBox_valueChanged(int i);
|
||||||
void on_ignoreIdleWindows_currentRowChanged(int idx);
|
void on_ignoreIdleWindows_currentRowChanged(int idx);
|
||||||
void on_ignoreIdleAdd_clicked();
|
void on_ignoreIdleAdd_clicked();
|
||||||
void on_ignoreIdleRemove_clicked();
|
void on_ignoreIdleRemove_clicked();
|
||||||
|
|
||||||
|
void on_randomAdd_clicked();
|
||||||
|
void on_randomRemove_clicked();
|
||||||
|
void on_randomScenesList_currentRowChanged(int idx);
|
||||||
|
|
||||||
|
void on_fileAdd_clicked();
|
||||||
|
void on_fileRemove_clicked();
|
||||||
|
void on_fileScenesList_currentRowChanged(int idx);
|
||||||
|
void on_browseButton_3_clicked();
|
||||||
|
|
||||||
|
void on_mediaAdd_clicked();
|
||||||
|
void on_mediaRemove_clicked();
|
||||||
|
|
||||||
void on_priorityUp_clicked();
|
void on_priorityUp_clicked();
|
||||||
void on_priorityDown_clicked();
|
void on_priorityDown_clicked();
|
||||||
|
|
||||||
@@ -111,13 +130,58 @@ public slots:
|
|||||||
void on_close_clicked();
|
void on_close_clicked();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/********************************************************************************
|
||||||
|
* Windowtitle helper
|
||||||
|
********************************************************************************/
|
||||||
void GetWindowList(std::vector<std::string> &windows);
|
void GetWindowList(std::vector<std::string> &windows);
|
||||||
void GetCurrentWindowTitle(std::string &title);
|
void GetCurrentWindowTitle(std::string &title);
|
||||||
pair<int, int> getCursorPos();
|
|
||||||
bool isFullscreen();
|
bool isFullscreen();
|
||||||
int secondsSinceLastInput();
|
|
||||||
bool isInFocus(const QString &exeToCheck);
|
|
||||||
void GetProcessList(QStringList &processes);
|
|
||||||
|
|
||||||
|
/********************************************************************************
|
||||||
|
* Screenregion helper
|
||||||
|
********************************************************************************/
|
||||||
|
pair<int, int> getCursorPos();
|
||||||
|
|
||||||
|
/********************************************************************************
|
||||||
|
* Idle detection helper
|
||||||
|
********************************************************************************/
|
||||||
|
int secondsSinceLastInput();
|
||||||
|
|
||||||
|
/********************************************************************************
|
||||||
|
* Executable helper
|
||||||
|
********************************************************************************/
|
||||||
|
void GetProcessList(QStringList &processes);
|
||||||
|
bool isInFocus(const QString &exeToCheck);
|
||||||
|
|
||||||
|
/********************************************************************************
|
||||||
|
* Sceneswitch helper
|
||||||
|
********************************************************************************/
|
||||||
|
struct obs_weak_source;
|
||||||
|
typedef struct obs_weak_source obs_weak_source_t;
|
||||||
|
|
||||||
|
obs_weak_source_t *getNextTransition(obs_weak_source_t *scene1,
|
||||||
|
obs_weak_source_t *scene2);
|
||||||
|
void switchScene(OBSWeakSource &scene, OBSWeakSource &transition,
|
||||||
|
unique_lock<mutex> &lock);
|
||||||
|
|
||||||
|
/********************************************************************************
|
||||||
|
* Hotkey helper
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
#define TOGGLE_HOTKEY_PATH "hotkey_toggle.txt"
|
||||||
|
#define STOP_HOTKEY_PATH "hotkey_stop.txt"
|
||||||
|
#define START_HOTKEY_PATH "hotkey_start.txt"
|
||||||
|
|
||||||
|
void stopHotkeyFunc(void *data, obs_hotkey_id id, obs_hotkey_t *hotkey,
|
||||||
|
bool pressed);
|
||||||
|
void startHotkeyFunc(void *data, obs_hotkey_id id, obs_hotkey_t *hotkey,
|
||||||
|
bool pressed);
|
||||||
|
void startStopToggleHotkeyFunc(void *data, obs_hotkey_id id,
|
||||||
|
obs_hotkey_t *hotkey, bool pressed);
|
||||||
|
void loadKeybinding(obs_hotkey_id hotkeyId, string path);
|
||||||
|
|
||||||
|
/********************************************************************************
|
||||||
|
* Main SwitcherData
|
||||||
|
********************************************************************************/
|
||||||
struct SwitcherData;
|
struct SwitcherData;
|
||||||
extern SwitcherData* switcher;
|
extern SwitcherData *switcher;
|
||||||
406
src/headers/switcher-data-structs.hpp
Normal file
406
src/headers/switcher-data-structs.hpp
Normal file
@@ -0,0 +1,406 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <chrono>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <thread>
|
||||||
|
#include <regex>
|
||||||
|
#include <mutex>
|
||||||
|
#include <fstream>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include "utility.hpp"
|
||||||
|
|
||||||
|
#define DEFAULT_INTERVAL 300
|
||||||
|
|
||||||
|
#define DEFAULT_IDLE_TIME 60
|
||||||
|
|
||||||
|
#define PREVIOUS_SCENE_NAME "Previous Scene"
|
||||||
|
|
||||||
|
#define READ_FILE_FUNC 0
|
||||||
|
#define ROUND_TRIP_FUNC 1
|
||||||
|
#define IDLE_FUNC 2
|
||||||
|
#define EXE_FUNC 3
|
||||||
|
#define SCREEN_REGION_FUNC 4
|
||||||
|
#define WINDOW_TITLE_FUNC 5
|
||||||
|
#define MEDIA_FUNC 6
|
||||||
|
|
||||||
|
#define DEFAULT_PRIORITY_0 READ_FILE_FUNC
|
||||||
|
#define DEFAULT_PRIORITY_1 ROUND_TRIP_FUNC
|
||||||
|
#define DEFAULT_PRIORITY_2 IDLE_FUNC
|
||||||
|
#define DEFAULT_PRIORITY_3 EXE_FUNC
|
||||||
|
#define DEFAULT_PRIORITY_4 SCREEN_REGION_FUNC
|
||||||
|
#define DEFAULT_PRIORITY_5 WINDOW_TITLE_FUNC
|
||||||
|
#define DEFAULT_PRIORITY_6 MEDIA_FUNC
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
/********************************************************************************
|
||||||
|
* Data structs for each scene switching method
|
||||||
|
********************************************************************************/
|
||||||
|
struct WindowSceneSwitch {
|
||||||
|
OBSWeakSource scene;
|
||||||
|
string window;
|
||||||
|
OBSWeakSource transition;
|
||||||
|
bool fullscreen;
|
||||||
|
|
||||||
|
inline WindowSceneSwitch(OBSWeakSource scene_, const char *window_,
|
||||||
|
OBSWeakSource transition_, bool fullscreen_)
|
||||||
|
: scene(scene_),
|
||||||
|
window(window_),
|
||||||
|
transition(transition_),
|
||||||
|
fullscreen(fullscreen_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ExecutableSceneSwitch {
|
||||||
|
OBSWeakSource mScene;
|
||||||
|
OBSWeakSource mTransition;
|
||||||
|
QString mExe;
|
||||||
|
bool mInFocus;
|
||||||
|
|
||||||
|
inline ExecutableSceneSwitch(OBSWeakSource scene,
|
||||||
|
OBSWeakSource transition,
|
||||||
|
const QString &exe, bool inFocus)
|
||||||
|
: mScene(scene),
|
||||||
|
mTransition(transition),
|
||||||
|
mExe(exe),
|
||||||
|
mInFocus(inFocus)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ScreenRegionSwitch {
|
||||||
|
OBSWeakSource scene;
|
||||||
|
OBSWeakSource transition;
|
||||||
|
int minX, minY, maxX, maxY;
|
||||||
|
string regionStr;
|
||||||
|
|
||||||
|
inline ScreenRegionSwitch(OBSWeakSource scene_,
|
||||||
|
OBSWeakSource transition_, int minX_,
|
||||||
|
int minY_, int maxX_, int maxY_,
|
||||||
|
string regionStr_)
|
||||||
|
: scene(scene_),
|
||||||
|
transition(transition_),
|
||||||
|
minX(minX_),
|
||||||
|
minY(minY_),
|
||||||
|
maxX(maxX_),
|
||||||
|
maxY(maxY_),
|
||||||
|
regionStr(regionStr_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SceneRoundTripSwitch {
|
||||||
|
OBSWeakSource scene1;
|
||||||
|
OBSWeakSource scene2;
|
||||||
|
OBSWeakSource transition;
|
||||||
|
int delay;
|
||||||
|
bool usePreviousScene;
|
||||||
|
string sceneRoundTripStr;
|
||||||
|
|
||||||
|
inline SceneRoundTripSwitch(OBSWeakSource scene1_,
|
||||||
|
OBSWeakSource scene2_,
|
||||||
|
OBSWeakSource transition_, int delay_,
|
||||||
|
bool usePreviousScene_, string str)
|
||||||
|
: scene1(scene1_),
|
||||||
|
scene2(scene2_),
|
||||||
|
transition(transition_),
|
||||||
|
delay(delay_),
|
||||||
|
usePreviousScene(usePreviousScene_),
|
||||||
|
sceneRoundTripStr(str)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RandomSwitch {
|
||||||
|
OBSWeakSource scene;
|
||||||
|
OBSWeakSource transition;
|
||||||
|
double delay;
|
||||||
|
string randomSwitchStr;
|
||||||
|
|
||||||
|
inline RandomSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
|
||||||
|
double delay_, string str)
|
||||||
|
: scene(scene_),
|
||||||
|
transition(transition_),
|
||||||
|
delay(delay_),
|
||||||
|
randomSwitchStr(str)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SceneTransition {
|
||||||
|
OBSWeakSource scene1;
|
||||||
|
OBSWeakSource scene2;
|
||||||
|
OBSWeakSource transition;
|
||||||
|
string sceneTransitionStr;
|
||||||
|
|
||||||
|
inline SceneTransition(OBSWeakSource scene1_, OBSWeakSource scene2_,
|
||||||
|
OBSWeakSource transition_,
|
||||||
|
string sceneTransitionStr_)
|
||||||
|
: scene1(scene1_),
|
||||||
|
scene2(scene2_),
|
||||||
|
transition(transition_),
|
||||||
|
sceneTransitionStr(sceneTransitionStr_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DefaultSceneTransition {
|
||||||
|
OBSWeakSource scene;
|
||||||
|
OBSWeakSource transition;
|
||||||
|
string sceneTransitionStr;
|
||||||
|
|
||||||
|
inline DefaultSceneTransition(OBSWeakSource scene_,
|
||||||
|
OBSWeakSource transition_,
|
||||||
|
string sceneTransitionStr_)
|
||||||
|
: scene(scene_),
|
||||||
|
transition(transition_),
|
||||||
|
sceneTransitionStr(sceneTransitionStr_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FileSwitch {
|
||||||
|
OBSWeakSource scene;
|
||||||
|
OBSWeakSource transition;
|
||||||
|
string file;
|
||||||
|
string text;
|
||||||
|
bool useRegex = false;
|
||||||
|
bool useTime = false;
|
||||||
|
QDateTime lastMod;
|
||||||
|
|
||||||
|
inline FileSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
|
||||||
|
const char *file_, const char *text_, bool useRegex_,
|
||||||
|
bool useTime_)
|
||||||
|
: scene(scene_),
|
||||||
|
transition(transition_),
|
||||||
|
file(file_),
|
||||||
|
text(text_),
|
||||||
|
useRegex(useRegex_),
|
||||||
|
useTime(useTime_),
|
||||||
|
lastMod()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FileIOData {
|
||||||
|
bool readEnabled = false;
|
||||||
|
string readPath;
|
||||||
|
bool writeEnabled = false;
|
||||||
|
string writePath;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IdleData {
|
||||||
|
bool idleEnable = false;
|
||||||
|
int time = DEFAULT_IDLE_TIME;
|
||||||
|
OBSWeakSource scene;
|
||||||
|
OBSWeakSource transition;
|
||||||
|
bool usePreviousScene;
|
||||||
|
bool alreadySwitched = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MediaSwitch {
|
||||||
|
OBSWeakSource scene;
|
||||||
|
OBSWeakSource source;
|
||||||
|
OBSWeakSource transition;
|
||||||
|
obs_media_state state;
|
||||||
|
uint64_t time;
|
||||||
|
time_restriction restriction;
|
||||||
|
bool matched;
|
||||||
|
|
||||||
|
inline MediaSwitch(OBSWeakSource scene_, OBSWeakSource source_,
|
||||||
|
OBSWeakSource transition_, obs_media_state state_,
|
||||||
|
time_restriction restriction_, uint64_t time_)
|
||||||
|
: scene(scene_),
|
||||||
|
source(source_),
|
||||||
|
transition(transition_),
|
||||||
|
state(state_),
|
||||||
|
restriction(restriction_),
|
||||||
|
time(time_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum { NO_SWITCH = 0, SWITCH = 1, RANDOM_SWITCH = 2 } NoMatch;
|
||||||
|
|
||||||
|
/********************************************************************************
|
||||||
|
* SwitcherData
|
||||||
|
********************************************************************************/
|
||||||
|
struct SwitcherData {
|
||||||
|
thread th;
|
||||||
|
condition_variable cv;
|
||||||
|
mutex m;
|
||||||
|
bool transitionActive = false;
|
||||||
|
bool waitForTransition = false;
|
||||||
|
condition_variable transitionCv;
|
||||||
|
bool startAtLaunch = false;
|
||||||
|
bool stop = false;
|
||||||
|
|
||||||
|
int interval = DEFAULT_INTERVAL;
|
||||||
|
|
||||||
|
obs_source_t *waitScene = NULL; //scene during which wait started
|
||||||
|
OBSWeakSource previousScene = NULL;
|
||||||
|
OBSWeakSource PreviousScene2 = NULL;
|
||||||
|
OBSWeakSource lastRandomScene;
|
||||||
|
OBSWeakSource nonMatchingScene;
|
||||||
|
NoMatch switchIfNotMatching = NO_SWITCH;
|
||||||
|
|
||||||
|
vector<WindowSceneSwitch> windowSwitches;
|
||||||
|
vector<string> ignoreIdleWindows;
|
||||||
|
string lastTitle;
|
||||||
|
|
||||||
|
vector<ScreenRegionSwitch> screenRegionSwitches;
|
||||||
|
|
||||||
|
vector<OBSWeakSource> pauseScenesSwitches;
|
||||||
|
|
||||||
|
vector<string> pauseWindowsSwitches;
|
||||||
|
|
||||||
|
vector<string> ignoreWindowsSwitches;
|
||||||
|
|
||||||
|
vector<SceneRoundTripSwitch> sceneRoundTripSwitches;
|
||||||
|
|
||||||
|
vector<RandomSwitch> randomSwitches;
|
||||||
|
|
||||||
|
FileIOData fileIO;
|
||||||
|
IdleData idleData;
|
||||||
|
vector<FileSwitch> fileSwitches;
|
||||||
|
|
||||||
|
vector<ExecutableSceneSwitch> executableSwitches;
|
||||||
|
|
||||||
|
bool autoStopEnable = false;
|
||||||
|
OBSWeakSource autoStopScene;
|
||||||
|
|
||||||
|
vector<SceneTransition> sceneTransitions;
|
||||||
|
vector<DefaultSceneTransition> defaultSceneTransitions;
|
||||||
|
|
||||||
|
vector<MediaSwitch> mediaSwitches;
|
||||||
|
|
||||||
|
vector<int> functionNamesByPriority = vector<int>{
|
||||||
|
DEFAULT_PRIORITY_0, DEFAULT_PRIORITY_1, DEFAULT_PRIORITY_2,
|
||||||
|
DEFAULT_PRIORITY_3, DEFAULT_PRIORITY_4, DEFAULT_PRIORITY_5,
|
||||||
|
DEFAULT_PRIORITY_6};
|
||||||
|
|
||||||
|
void Thread();
|
||||||
|
void Start();
|
||||||
|
void Stop();
|
||||||
|
|
||||||
|
bool sceneChangedDuringWait();
|
||||||
|
bool prioFuncsValid();
|
||||||
|
void writeSceneInfoToFile();
|
||||||
|
void setDefaultSceneTransitions();
|
||||||
|
void autoStopStreamAndRecording();
|
||||||
|
bool checkPause();
|
||||||
|
void checkSceneRoundTrip(bool &match, OBSWeakSource &scene,
|
||||||
|
OBSWeakSource &transition,
|
||||||
|
unique_lock<mutex> &lock);
|
||||||
|
void checkIdleSwitch(bool &match, OBSWeakSource &scene,
|
||||||
|
OBSWeakSource &transition);
|
||||||
|
void checkWindowTitleSwitch(bool &match, OBSWeakSource &scene,
|
||||||
|
OBSWeakSource &transition);
|
||||||
|
void checkExeSwitch(bool &match, OBSWeakSource &scene,
|
||||||
|
OBSWeakSource &transition);
|
||||||
|
void checkScreenRegionSwitch(bool &match, OBSWeakSource &scene,
|
||||||
|
OBSWeakSource &transition);
|
||||||
|
void checkSwitchInfoFromFile(bool &match, OBSWeakSource &scene,
|
||||||
|
OBSWeakSource &transition);
|
||||||
|
void checkFileContent(bool &match, OBSWeakSource &scene,
|
||||||
|
OBSWeakSource &transition);
|
||||||
|
void checkRandom(bool &match, OBSWeakSource &scene,
|
||||||
|
OBSWeakSource &transition, int &delay);
|
||||||
|
void checkMediaSwitch(bool &match, OBSWeakSource &scene,
|
||||||
|
OBSWeakSource &transition);
|
||||||
|
|
||||||
|
void Prune()
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < windowSwitches.size(); i++) {
|
||||||
|
WindowSceneSwitch &s = windowSwitches[i];
|
||||||
|
if (!WeakSourceValid(s.scene) ||
|
||||||
|
!WeakSourceValid(s.transition))
|
||||||
|
windowSwitches.erase(windowSwitches.begin() +
|
||||||
|
i--);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nonMatchingScene && !WeakSourceValid(nonMatchingScene)) {
|
||||||
|
switchIfNotMatching = NO_SWITCH;
|
||||||
|
nonMatchingScene = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < randomSwitches.size(); i++) {
|
||||||
|
RandomSwitch &s = randomSwitches[i];
|
||||||
|
if (!WeakSourceValid(s.scene) ||
|
||||||
|
!WeakSourceValid(s.transition))
|
||||||
|
randomSwitches.erase(randomSwitches.begin() +
|
||||||
|
i--);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < screenRegionSwitches.size(); i++) {
|
||||||
|
ScreenRegionSwitch &s = screenRegionSwitches[i];
|
||||||
|
if (!WeakSourceValid(s.scene) ||
|
||||||
|
!WeakSourceValid(s.transition))
|
||||||
|
screenRegionSwitches.erase(
|
||||||
|
screenRegionSwitches.begin() + i--);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < pauseScenesSwitches.size(); i++) {
|
||||||
|
OBSWeakSource &scene = pauseScenesSwitches[i];
|
||||||
|
if (!WeakSourceValid(scene))
|
||||||
|
pauseScenesSwitches.erase(
|
||||||
|
pauseScenesSwitches.begin() + i--);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < sceneRoundTripSwitches.size(); i++) {
|
||||||
|
SceneRoundTripSwitch &s = sceneRoundTripSwitches[i];
|
||||||
|
if (!WeakSourceValid(s.scene1) ||
|
||||||
|
(!s.usePreviousScene &&
|
||||||
|
!WeakSourceValid(s.scene2)) ||
|
||||||
|
!WeakSourceValid(s.transition))
|
||||||
|
sceneRoundTripSwitches.erase(
|
||||||
|
sceneRoundTripSwitches.begin() + i--);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!WeakSourceValid(autoStopScene)) {
|
||||||
|
autoStopScene = nullptr;
|
||||||
|
autoStopEnable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < sceneTransitions.size(); i++) {
|
||||||
|
SceneTransition &s = sceneTransitions[i];
|
||||||
|
if (!WeakSourceValid(s.scene1) ||
|
||||||
|
!WeakSourceValid(s.scene2) ||
|
||||||
|
!WeakSourceValid(s.transition))
|
||||||
|
sceneTransitions.erase(
|
||||||
|
sceneTransitions.begin() + i--);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < defaultSceneTransitions.size(); i++) {
|
||||||
|
DefaultSceneTransition &s = defaultSceneTransitions[i];
|
||||||
|
if (!WeakSourceValid(s.scene) ||
|
||||||
|
!WeakSourceValid(s.transition))
|
||||||
|
defaultSceneTransitions.erase(
|
||||||
|
defaultSceneTransitions.begin() + i--);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < executableSwitches.size(); i++) {
|
||||||
|
ExecutableSceneSwitch &s = executableSwitches[i];
|
||||||
|
if (!WeakSourceValid(s.mScene) ||
|
||||||
|
!WeakSourceValid(s.mTransition))
|
||||||
|
executableSwitches.erase(
|
||||||
|
executableSwitches.begin() + i--);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < fileSwitches.size(); i++) {
|
||||||
|
FileSwitch &s = fileSwitches[i];
|
||||||
|
if (!WeakSourceValid(s.scene) ||
|
||||||
|
!WeakSourceValid(s.transition))
|
||||||
|
fileSwitches.erase(fileSwitches.begin() + i--);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!idleData.usePreviousScene &&
|
||||||
|
!WeakSourceValid(idleData.scene) ||
|
||||||
|
!WeakSourceValid(idleData.transition)) {
|
||||||
|
idleData.idleEnable = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inline ~SwitcherData() { Stop(); }
|
||||||
|
};
|
||||||
232
src/headers/utility.hpp
Normal file
232
src/headers/utility.hpp
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <obs.hpp>
|
||||||
|
#include <QString>
|
||||||
|
#include <obs-frontend-api.h>
|
||||||
|
#include "switcher-data-structs.hpp"
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
static inline bool WeakSourceValid(obs_weak_source_t* ws)
|
||||||
|
{
|
||||||
|
obs_source_t* source = obs_weak_source_get_source(ws);
|
||||||
|
if (source)
|
||||||
|
obs_source_release(source);
|
||||||
|
return !!source;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline QString MakeSwitchName(const QString &scene, const QString &value,
|
||||||
|
const QString &transition, bool fullscreen)
|
||||||
|
{
|
||||||
|
if (!fullscreen)
|
||||||
|
return QStringLiteral("[") + scene + QStringLiteral(", ") +
|
||||||
|
transition + QStringLiteral("]: ") + value;
|
||||||
|
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition +
|
||||||
|
QStringLiteral("]: ") + value +
|
||||||
|
QStringLiteral(" (only if window is fullscreen)");
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline QString MakeSwitchNameExecutable(const QString &scene,
|
||||||
|
const QString &value,
|
||||||
|
const QString &transition,
|
||||||
|
bool inFocus)
|
||||||
|
{
|
||||||
|
if (!inFocus)
|
||||||
|
return QStringLiteral("[") + scene + QStringLiteral(", ") +
|
||||||
|
transition + QStringLiteral("]: ") + value;
|
||||||
|
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition +
|
||||||
|
QStringLiteral("]: ") + value +
|
||||||
|
QStringLiteral(" (only if window is focused)");
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline QString MakeScreenRegionSwitchName(const QString &scene,
|
||||||
|
const QString &transition,
|
||||||
|
int minX, int minY, int maxX,
|
||||||
|
int maxY)
|
||||||
|
{
|
||||||
|
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition +
|
||||||
|
QStringLiteral("]: ") + QString::number(minX) +
|
||||||
|
QStringLiteral(", ") + QString::number(minY) +
|
||||||
|
QStringLiteral(" x ") + QString::number(maxX) +
|
||||||
|
QStringLiteral(", ") + QString::number(maxY);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline QString MakeSceneRoundTripSwitchName(const QString &scene1,
|
||||||
|
const QString &scene2,
|
||||||
|
const QString &transition,
|
||||||
|
double delay)
|
||||||
|
{
|
||||||
|
return scene1 + QStringLiteral(" -> wait for ") +
|
||||||
|
QString::number(delay) + QStringLiteral(" seconds -> ") +
|
||||||
|
scene2 + QStringLiteral(" (using ") + transition +
|
||||||
|
QStringLiteral(" transition)");
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline QString MakeSceneTransitionName(const QString &scene1,
|
||||||
|
const QString &scene2,
|
||||||
|
const QString &transition)
|
||||||
|
{
|
||||||
|
return scene1 + QStringLiteral(" --- ") + transition +
|
||||||
|
QStringLiteral(" --> ") + scene2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline QString MakeDefaultSceneTransitionName(const QString &scene,
|
||||||
|
const QString &transition)
|
||||||
|
{
|
||||||
|
return scene + QStringLiteral(" --> ") + transition;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline QString MakeRandomSwitchName(const QString &scene,
|
||||||
|
const QString &transition,
|
||||||
|
double &delay)
|
||||||
|
{
|
||||||
|
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition +
|
||||||
|
QStringLiteral("]: ") + QString::number(delay) +
|
||||||
|
QStringLiteral(" seconds");
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline QString MakeFileSwitchName(const QString &scene,
|
||||||
|
const QString &transition,
|
||||||
|
const QString &fileName,
|
||||||
|
const QString &text, bool useRegex,
|
||||||
|
bool useTime)
|
||||||
|
{
|
||||||
|
QString switchName = QStringLiteral("Switch to ") + scene +
|
||||||
|
QStringLiteral(" using ") + transition +
|
||||||
|
QStringLiteral(" if ") + fileName;
|
||||||
|
if (useTime)
|
||||||
|
switchName += QStringLiteral(" was modified and");
|
||||||
|
switchName += QStringLiteral(" contains");
|
||||||
|
if (useRegex)
|
||||||
|
switchName += QStringLiteral(" (RegEx): \n\"");
|
||||||
|
else
|
||||||
|
switchName += QStringLiteral(": \n\"");
|
||||||
|
if (text.length() > 30)
|
||||||
|
switchName += text.left(27) + QStringLiteral("...\"");
|
||||||
|
else
|
||||||
|
switchName += text + QStringLiteral("\"");
|
||||||
|
|
||||||
|
return switchName;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
TIME_RESTRICTION_NONE,
|
||||||
|
TIME_RESTRICTION_SHORTER,
|
||||||
|
TIME_RESTRICTION_LONGER,
|
||||||
|
TIME_RESTRICTION_REMAINING_SHORTER,
|
||||||
|
TIME_RESTRICTION_REMAINING_LONGER,
|
||||||
|
} time_restriction;
|
||||||
|
|
||||||
|
static inline QString
|
||||||
|
MakeMediaSwitchName(const QString &source, const QString &scene,
|
||||||
|
const QString &transition, obs_media_state state,
|
||||||
|
time_restriction restriction, uint64_t time)
|
||||||
|
{
|
||||||
|
QString switchName = QStringLiteral("Switch to ") + scene +
|
||||||
|
QStringLiteral(" using ") + transition +
|
||||||
|
QStringLiteral(" if ") + source +
|
||||||
|
QStringLiteral(" state is ");
|
||||||
|
if (state == OBS_MEDIA_STATE_NONE) {
|
||||||
|
switchName += QStringLiteral("none");
|
||||||
|
} else if (state == OBS_MEDIA_STATE_PLAYING) {
|
||||||
|
switchName += QStringLiteral("playing");
|
||||||
|
} else if (state == OBS_MEDIA_STATE_OPENING) {
|
||||||
|
switchName += QStringLiteral("opening");
|
||||||
|
} else if (state == OBS_MEDIA_STATE_BUFFERING) {
|
||||||
|
switchName += QStringLiteral("buffering");
|
||||||
|
} else if (state == OBS_MEDIA_STATE_PAUSED) {
|
||||||
|
switchName += QStringLiteral("paused");
|
||||||
|
} else if (state == OBS_MEDIA_STATE_STOPPED) {
|
||||||
|
switchName += QStringLiteral("stopped");
|
||||||
|
} else if (state == OBS_MEDIA_STATE_ENDED) {
|
||||||
|
switchName += QStringLiteral("ended");
|
||||||
|
} else if (state == OBS_MEDIA_STATE_ERROR) {
|
||||||
|
switchName += QStringLiteral("error");
|
||||||
|
}
|
||||||
|
if (restriction == TIME_RESTRICTION_SHORTER) {
|
||||||
|
switchName += QStringLiteral(" and time shorter than ");
|
||||||
|
} else if (restriction == TIME_RESTRICTION_LONGER) {
|
||||||
|
switchName += QStringLiteral(" and time longer than ");
|
||||||
|
} else if (restriction == TIME_RESTRICTION_REMAINING_SHORTER) {
|
||||||
|
switchName +=
|
||||||
|
QStringLiteral(" and time remaining shorter than ");
|
||||||
|
} else if (restriction == TIME_RESTRICTION_REMAINING_LONGER) {
|
||||||
|
switchName +=
|
||||||
|
QStringLiteral(" and time remaining longer than ");
|
||||||
|
}
|
||||||
|
if (restriction != TIME_RESTRICTION_NONE) {
|
||||||
|
switchName += std::to_string(time).c_str();
|
||||||
|
switchName += QStringLiteral(" ms");
|
||||||
|
}
|
||||||
|
return switchName;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline string GetWeakSourceName(obs_weak_source_t *weak_source)
|
||||||
|
{
|
||||||
|
string name;
|
||||||
|
|
||||||
|
obs_source_t *source = obs_weak_source_get_source(weak_source);
|
||||||
|
if (source) {
|
||||||
|
name = obs_source_get_name(source);
|
||||||
|
obs_source_release(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline OBSWeakSource GetWeakSourceByName(const char *name)
|
||||||
|
{
|
||||||
|
OBSWeakSource weak;
|
||||||
|
obs_source_t *source = obs_get_source_by_name(name);
|
||||||
|
if (source) {
|
||||||
|
weak = obs_source_get_weak_source(source);
|
||||||
|
obs_weak_source_release(weak);
|
||||||
|
obs_source_release(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
return weak;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline OBSWeakSource GetWeakSourceByQString(const QString &name)
|
||||||
|
{
|
||||||
|
return GetWeakSourceByName(name.toUtf8().constData());
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline OBSWeakSource GetWeakTransitionByName(const char *transitionName)
|
||||||
|
{
|
||||||
|
OBSWeakSource weak;
|
||||||
|
obs_source_t *source = nullptr;
|
||||||
|
|
||||||
|
if (strcmp(transitionName, "Default") == 0) {
|
||||||
|
source = obs_frontend_get_current_transition();
|
||||||
|
weak = obs_source_get_weak_source(source);
|
||||||
|
obs_source_release(source);
|
||||||
|
obs_weak_source_release(weak);
|
||||||
|
return weak;
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_frontend_source_list *transitions = new obs_frontend_source_list();
|
||||||
|
obs_frontend_get_transitions(transitions);
|
||||||
|
bool match = false;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < transitions->sources.num; i++) {
|
||||||
|
const char *name =
|
||||||
|
obs_source_get_name(transitions->sources.array[i]);
|
||||||
|
if (strcmp(transitionName, name) == 0) {
|
||||||
|
match = true;
|
||||||
|
source = transitions->sources.array[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
weak = obs_source_get_weak_source(source);
|
||||||
|
obs_weak_source_release(weak);
|
||||||
|
}
|
||||||
|
obs_frontend_source_list_free(transitions);
|
||||||
|
|
||||||
|
return weak;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline OBSWeakSource GetWeakTransitionByQString(const QString &name)
|
||||||
|
{
|
||||||
|
return GetWeakTransitionByName(name.toUtf8().constData());
|
||||||
|
}
|
||||||
142
src/hotkey.cpp
Normal file
142
src/hotkey.cpp
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
#include <obs-module.h>
|
||||||
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
|
||||||
|
void startHotkeyFunc(void* data, obs_hotkey_id id, obs_hotkey_t* hotkey, bool pressed)
|
||||||
|
{
|
||||||
|
UNUSED_PARAMETER(data);
|
||||||
|
UNUSED_PARAMETER(hotkey);
|
||||||
|
|
||||||
|
if (pressed)
|
||||||
|
{
|
||||||
|
if (!switcher->th.joinable())
|
||||||
|
switcher->Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_data_array* hotkeyData = obs_hotkey_save(id);
|
||||||
|
|
||||||
|
if (hotkeyData != NULL)
|
||||||
|
{
|
||||||
|
char* path = obs_module_config_path("");
|
||||||
|
ofstream file;
|
||||||
|
file.open(string(path).append(START_HOTKEY_PATH), ofstream::trunc);
|
||||||
|
if (file.is_open())
|
||||||
|
{
|
||||||
|
size_t num = obs_data_array_count(hotkeyData);
|
||||||
|
for (size_t i = 0; i < num; i++)
|
||||||
|
{
|
||||||
|
obs_data_t* data = obs_data_array_item(hotkeyData, i);
|
||||||
|
string temp = obs_data_get_json(data);
|
||||||
|
obs_data_release(data);
|
||||||
|
file << temp;
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
bfree(path);
|
||||||
|
}
|
||||||
|
obs_data_array_release(hotkeyData);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopHotkeyFunc(void* data, obs_hotkey_id id, obs_hotkey_t* hotkey, bool pressed)
|
||||||
|
{
|
||||||
|
UNUSED_PARAMETER(data);
|
||||||
|
UNUSED_PARAMETER(hotkey);
|
||||||
|
|
||||||
|
if (pressed)
|
||||||
|
{
|
||||||
|
if (switcher->th.joinable())
|
||||||
|
switcher->Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_data_array* hotkeyData = obs_hotkey_save(id);
|
||||||
|
|
||||||
|
if (hotkeyData != NULL)
|
||||||
|
{
|
||||||
|
char* path = obs_module_config_path("");
|
||||||
|
ofstream file;
|
||||||
|
file.open(string(path).append(STOP_HOTKEY_PATH), ofstream::trunc);
|
||||||
|
if (file.is_open())
|
||||||
|
{
|
||||||
|
size_t num = obs_data_array_count(hotkeyData);
|
||||||
|
for (size_t i = 0; i < num; i++)
|
||||||
|
{
|
||||||
|
obs_data_t* data = obs_data_array_item(hotkeyData, i);
|
||||||
|
string temp = obs_data_get_json(data);
|
||||||
|
obs_data_release(data);
|
||||||
|
file << temp;
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
bfree(path);
|
||||||
|
}
|
||||||
|
obs_data_array_release(hotkeyData);
|
||||||
|
}
|
||||||
|
|
||||||
|
void startStopToggleHotkeyFunc(void* data, obs_hotkey_id id, obs_hotkey_t* hotkey, bool pressed)
|
||||||
|
{
|
||||||
|
UNUSED_PARAMETER(data);
|
||||||
|
UNUSED_PARAMETER(hotkey);
|
||||||
|
|
||||||
|
if (pressed)
|
||||||
|
{
|
||||||
|
if (switcher->th.joinable())
|
||||||
|
switcher->Stop();
|
||||||
|
else
|
||||||
|
switcher->Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_data_array* hotkeyData = obs_hotkey_save(id);
|
||||||
|
|
||||||
|
if (hotkeyData != NULL)
|
||||||
|
{
|
||||||
|
char* path = obs_module_config_path("");
|
||||||
|
ofstream file;
|
||||||
|
file.open(string(path).append(TOGGLE_HOTKEY_PATH), ofstream::trunc);
|
||||||
|
if (file.is_open())
|
||||||
|
{
|
||||||
|
size_t num = obs_data_array_count(hotkeyData);
|
||||||
|
for (size_t i = 0; i < num; i++)
|
||||||
|
{
|
||||||
|
obs_data_t* data = obs_data_array_item(hotkeyData, i);
|
||||||
|
string temp = obs_data_get_json(data);
|
||||||
|
obs_data_release(data);
|
||||||
|
file << temp;
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
bfree(path);
|
||||||
|
}
|
||||||
|
obs_data_array_release(hotkeyData);
|
||||||
|
}
|
||||||
|
|
||||||
|
string loadConfigFile(string filename)
|
||||||
|
{
|
||||||
|
ifstream settingsFile;
|
||||||
|
char* path = obs_module_config_path("");
|
||||||
|
string value;
|
||||||
|
|
||||||
|
settingsFile.open(string(path).append(filename));
|
||||||
|
if (settingsFile.is_open())
|
||||||
|
{
|
||||||
|
settingsFile.seekg(0, ios::end);
|
||||||
|
value.reserve(settingsFile.tellg());
|
||||||
|
settingsFile.seekg(0, ios::beg);
|
||||||
|
value.assign((istreambuf_iterator<char>(settingsFile)), istreambuf_iterator<char>());
|
||||||
|
settingsFile.close();
|
||||||
|
}
|
||||||
|
bfree(path);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadKeybinding(obs_hotkey_id hotkeyId, string path)
|
||||||
|
{
|
||||||
|
string bindings = loadConfigFile(path);
|
||||||
|
if (!bindings.empty())
|
||||||
|
{
|
||||||
|
obs_data_array_t* hotkeyData = obs_data_array_create();
|
||||||
|
obs_data_t* data = obs_data_create_from_json(bindings.c_str());
|
||||||
|
obs_data_array_insert(hotkeyData, 0, data);
|
||||||
|
obs_data_release(data);
|
||||||
|
obs_hotkey_load(hotkeyId, hotkeyData);
|
||||||
|
obs_data_array_release(hotkeyData);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
|
||||||
void SwitcherData::checkIdleSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
|
void SwitcherData::checkIdleSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
|
||||||
{
|
{
|
||||||
@@ -41,10 +41,15 @@ void SwitcherData::checkIdleSwitch(bool& match, OBSWeakSource& scene, OBSWeakSou
|
|||||||
|
|
||||||
if (!ignoreIdle && secondsSinceLastInput() > idleData.time)
|
if (!ignoreIdle && secondsSinceLastInput() > idleData.time)
|
||||||
{
|
{
|
||||||
scene = idleData.scene;
|
if (idleData.alreadySwitched)
|
||||||
|
return;
|
||||||
|
scene = (idleData.usePreviousScene) ? previousScene : idleData.scene;
|
||||||
transition = idleData.transition;
|
transition = idleData.transition;
|
||||||
match = true;
|
match = true;
|
||||||
|
idleData.alreadySwitched = true;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
idleData.alreadySwitched = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneSwitcher::on_idleCheckBox_stateChanged(int state)
|
void SceneSwitcher::on_idleCheckBox_stateChanged(int state)
|
||||||
@@ -83,6 +88,7 @@ void SceneSwitcher::UpdateIdleDataTransition(const QString& name)
|
|||||||
|
|
||||||
void SceneSwitcher::UpdateIdleDataScene(const QString& name)
|
void SceneSwitcher::UpdateIdleDataScene(const QString& name)
|
||||||
{
|
{
|
||||||
|
switcher->idleData.usePreviousScene = (name == PREVIOUS_SCENE_NAME);
|
||||||
obs_source_t* scene = obs_get_source_by_name(name.toUtf8().constData());
|
obs_source_t* scene = obs_get_source_by_name(name.toUtf8().constData());
|
||||||
obs_weak_source_t* ws = obs_source_get_weak_source(scene);
|
obs_weak_source_t* ws = obs_source_get_weak_source(scene);
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
#undef Status
|
#undef Status
|
||||||
#undef Unsorted
|
#undef Unsorted
|
||||||
#include <util/platform.h>
|
#include <util/platform.h>
|
||||||
#include "advanced-scene-switcher.hpp"
|
#include "../headers/advanced-scene-switcher.hpp"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
@@ -150,7 +150,9 @@ static std::string GetWindowTitle(size_t i)
|
|||||||
std::string windowTitle;
|
std::string windowTitle;
|
||||||
char* name;
|
char* name;
|
||||||
|
|
||||||
int status = XFetchName(disp(), w, &name);
|
XTextProperty text;
|
||||||
|
int status = XGetWMName(disp(), w, &text);
|
||||||
|
name = reinterpret_cast<char*>(text.value);
|
||||||
if (status >= Success && name != nullptr)
|
if (status >= Success && name != nullptr)
|
||||||
{
|
{
|
||||||
std::string str(name);
|
std::string str(name);
|
||||||
@@ -201,7 +203,9 @@ void GetCurrentWindowTitle(string &title)
|
|||||||
&bytes,
|
&bytes,
|
||||||
(uint8_t**)&data);
|
(uint8_t**)&data);
|
||||||
|
|
||||||
int status = XFetchName(disp(), data[0], &name);
|
XTextProperty text;
|
||||||
|
int status = XGetWMName(disp(), data[0], &text);
|
||||||
|
name = reinterpret_cast<char*>(text.value);
|
||||||
|
|
||||||
if (status >= Success && name != nullptr) {
|
if (status >= Success && name != nullptr) {
|
||||||
std::string str(name);
|
std::string str(name);
|
||||||
@@ -232,6 +236,7 @@ pair<int, int> getCursorPos()
|
|||||||
{
|
{
|
||||||
pos = pair<int, int> (root_x,root_y);
|
pos = pair<int, int> (root_x,root_y);
|
||||||
}
|
}
|
||||||
|
XCloseDisplay(dpy);
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,5 +323,3 @@ int secondsSinceLastInput()
|
|||||||
|
|
||||||
return idle_time;
|
return idle_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
87
src/media-switch.cpp
Normal file
87
src/media-switch.cpp
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
#include <obs-module.h>
|
||||||
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
|
||||||
|
void SceneSwitcher::on_mediaAdd_clicked()
|
||||||
|
{
|
||||||
|
QString sourceName = ui->mediaSources->currentText();
|
||||||
|
QString sceneName = ui->mediaScenes->currentText();
|
||||||
|
QString transitionName = ui->mediaTransitions->currentText();
|
||||||
|
obs_media_state state =
|
||||||
|
(obs_media_state)ui->mediaStates->currentIndex();
|
||||||
|
time_restriction restriction =
|
||||||
|
(time_restriction)ui->mediaTimeRestrictions->currentIndex();
|
||||||
|
uint64_t time = ui->mediaTime->value();
|
||||||
|
|
||||||
|
if (sceneName.isEmpty() || transitionName.isEmpty() ||
|
||||||
|
sourceName.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
OBSWeakSource source = GetWeakSourceByQString(sourceName);
|
||||||
|
OBSWeakSource scene = GetWeakSourceByQString(sceneName);
|
||||||
|
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
|
||||||
|
|
||||||
|
QString switchText = MakeMediaSwitchName(sourceName, sceneName,
|
||||||
|
transitionName, state,
|
||||||
|
restriction, time);
|
||||||
|
QVariant v = QVariant::fromValue(switchText);
|
||||||
|
|
||||||
|
QListWidgetItem *item =
|
||||||
|
new QListWidgetItem(switchText, ui->mediaSwitches);
|
||||||
|
item->setData(Qt::UserRole, v);
|
||||||
|
|
||||||
|
lock_guard<mutex> lock(switcher->m);
|
||||||
|
switcher->mediaSwitches.emplace_back(scene, source, transition, state,
|
||||||
|
restriction, time);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneSwitcher::on_mediaRemove_clicked()
|
||||||
|
{
|
||||||
|
QListWidgetItem *item = ui->mediaSwitches->currentItem();
|
||||||
|
if (!item)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int idx = ui->mediaSwitches->currentRow();
|
||||||
|
if (idx == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
{
|
||||||
|
lock_guard<mutex> lock(switcher->m);
|
||||||
|
|
||||||
|
auto &switches = switcher->mediaSwitches;
|
||||||
|
switches.erase(switches.begin() + idx);
|
||||||
|
}
|
||||||
|
qDeleteAll(ui->mediaSwitches->selectedItems());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitcherData::checkMediaSwitch(bool &match, OBSWeakSource &scene,
|
||||||
|
OBSWeakSource &transition)
|
||||||
|
{
|
||||||
|
for (MediaSwitch &mediaSwitch : mediaSwitches) {
|
||||||
|
obs_source_t *source =
|
||||||
|
obs_weak_source_get_source(mediaSwitch.source);
|
||||||
|
auto duration = obs_source_media_get_duration(source);
|
||||||
|
auto time = obs_source_media_get_time(source);
|
||||||
|
obs_media_state state = obs_source_media_get_state(source);
|
||||||
|
bool matched =
|
||||||
|
state == mediaSwitch.state &&
|
||||||
|
(mediaSwitch.restriction == TIME_RESTRICTION_NONE ||
|
||||||
|
(mediaSwitch.restriction == TIME_RESTRICTION_LONGER &&
|
||||||
|
time > mediaSwitch.time) ||
|
||||||
|
(mediaSwitch.restriction == TIME_RESTRICTION_SHORTER &&
|
||||||
|
time < mediaSwitch.time) ||
|
||||||
|
(mediaSwitch.restriction ==
|
||||||
|
TIME_RESTRICTION_REMAINING_SHORTER &&
|
||||||
|
duration > time &&
|
||||||
|
duration - time < mediaSwitch.time) ||
|
||||||
|
(mediaSwitch.restriction ==
|
||||||
|
TIME_RESTRICTION_REMAINING_LONGER &&
|
||||||
|
duration > time &&
|
||||||
|
duration - time > mediaSwitch.time));
|
||||||
|
if (matched && !mediaSwitch.matched) {
|
||||||
|
match = true;
|
||||||
|
scene = mediaSwitch.scene;
|
||||||
|
transition = mediaSwitch.transition;
|
||||||
|
}
|
||||||
|
mediaSwitch.matched = matched;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
#import <Carbon/Carbon.h>
|
#import <Carbon/Carbon.h>
|
||||||
#include <Carbon/Carbon.h>
|
#include <Carbon/Carbon.h>
|
||||||
#include <util/platform.h>
|
#include <util/platform.h>
|
||||||
#include "advanced-scene-switcher.hpp"
|
#include "../headers/advanced-scene-switcher.hpp"
|
||||||
|
|
||||||
|
|
||||||
void GetWindowList(vector<string> &windows)
|
void GetWindowList(vector<string> &windows)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
|
||||||
void SceneSwitcher::on_pauseScenesAdd_clicked()
|
void SceneSwitcher::on_pauseScenesAdd_clicked()
|
||||||
{
|
{
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
|
||||||
void SceneSwitcher::on_priorityUp_clicked()
|
void SceneSwitcher::on_priorityUp_clicked()
|
||||||
{
|
{
|
||||||
@@ -27,29 +27,16 @@ void SceneSwitcher::on_priorityDown_clicked()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool prioStrValid(string s)
|
|
||||||
{
|
|
||||||
if (s == WINDOW_TITLE_FUNC)
|
|
||||||
return true;
|
|
||||||
if (s == SCREEN_REGION_FUNC)
|
|
||||||
return true;
|
|
||||||
if (s == ROUND_TRIP_FUNC)
|
|
||||||
return true;
|
|
||||||
if (s == (IDLE_FUNC))
|
|
||||||
return true;
|
|
||||||
if (s == EXE_FUNC)
|
|
||||||
return true;
|
|
||||||
if (s == READ_FILE_FUNC)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool SwitcherData::prioFuncsValid()
|
bool SwitcherData::prioFuncsValid()
|
||||||
{
|
{
|
||||||
for (string f : functionNamesByPriority)
|
auto it = std::unique(functionNamesByPriority.begin(), functionNamesByPriority.end());
|
||||||
|
bool wasUnique = (it == functionNamesByPriority.end());
|
||||||
|
if (!wasUnique)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (int p : functionNamesByPriority)
|
||||||
{
|
{
|
||||||
if (!prioStrValid(f))
|
if (p < 0 || p > 6)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
144
src/random.cpp
Normal file
144
src/random.cpp
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
void SceneSwitcher::on_randomScenesList_currentRowChanged(int idx)
|
||||||
|
{
|
||||||
|
if (loading)
|
||||||
|
return;
|
||||||
|
if (idx == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QListWidgetItem* item = ui->randomScenesList->item(idx);
|
||||||
|
|
||||||
|
QString randomSceneStr = item->data(Qt::UserRole).toString();
|
||||||
|
|
||||||
|
lock_guard<mutex> lock(switcher->m);
|
||||||
|
for (auto& s : switcher->randomSwitches)
|
||||||
|
{
|
||||||
|
if (randomSceneStr.compare(s.randomSwitchStr.c_str()) == 0)
|
||||||
|
{
|
||||||
|
QString sceneName = GetWeakSourceName(s.scene).c_str();
|
||||||
|
QString transitionName = GetWeakSourceName(s.transition).c_str();
|
||||||
|
ui->randomScenes->setCurrentText(sceneName);
|
||||||
|
ui->randomSpinBox->setValue(s.delay);
|
||||||
|
ui->randomTransitions->setCurrentText(transitionName);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int SceneSwitcher::randomFindByData(const QString& randomStr)
|
||||||
|
{
|
||||||
|
int count = ui->randomScenesList->count();
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
QListWidgetItem* item = ui->randomScenesList->item(i);
|
||||||
|
QString str = item->data(Qt::UserRole).toString();
|
||||||
|
|
||||||
|
if (str == randomStr)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneSwitcher::on_randomAdd_clicked()
|
||||||
|
{
|
||||||
|
QString sceneName = ui->randomScenes->currentText();
|
||||||
|
QString transitionName = ui->randomTransitions->currentText();
|
||||||
|
double delay = ui->randomSpinBox->value();
|
||||||
|
|
||||||
|
|
||||||
|
if (sceneName.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
OBSWeakSource source = GetWeakSourceByQString(sceneName);
|
||||||
|
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
|
||||||
|
|
||||||
|
|
||||||
|
QString text = MakeRandomSwitchName(sceneName, transitionName, delay);
|
||||||
|
QVariant v = QVariant::fromValue(text);
|
||||||
|
|
||||||
|
int idx = randomFindByData(text);
|
||||||
|
|
||||||
|
if (idx == -1)
|
||||||
|
{
|
||||||
|
lock_guard<mutex> lock(switcher->m);
|
||||||
|
switcher->randomSwitches.emplace_back(
|
||||||
|
source, transition, delay, text.toUtf8().constData());
|
||||||
|
|
||||||
|
QListWidgetItem* item = new QListWidgetItem(text, ui->randomScenesList);
|
||||||
|
item->setData(Qt::UserRole, v);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QListWidgetItem* item = ui->randomScenesList->item(idx);
|
||||||
|
item->setText(text);
|
||||||
|
|
||||||
|
{
|
||||||
|
lock_guard<mutex> lock(switcher->m);
|
||||||
|
for (auto& s : switcher->randomSwitches)
|
||||||
|
{
|
||||||
|
if (s.scene == source)
|
||||||
|
{
|
||||||
|
s.delay = delay;
|
||||||
|
s.transition = transition;
|
||||||
|
s.randomSwitchStr = text.toUtf8().constData();;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->randomScenesList->sortItems();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneSwitcher::on_randomRemove_clicked()
|
||||||
|
{
|
||||||
|
QListWidgetItem* item = ui->randomScenesList->currentItem();
|
||||||
|
if (!item)
|
||||||
|
return;
|
||||||
|
|
||||||
|
string text = item->data(Qt::UserRole).toString().toUtf8().constData();
|
||||||
|
|
||||||
|
{
|
||||||
|
lock_guard<mutex> lock(switcher->m);
|
||||||
|
auto& switches = switcher->randomSwitches;
|
||||||
|
|
||||||
|
for (auto it = switches.begin(); it != switches.end(); ++it)
|
||||||
|
{
|
||||||
|
auto& s = *it;
|
||||||
|
|
||||||
|
if (s.randomSwitchStr == text)
|
||||||
|
{
|
||||||
|
switches.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete item;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitcherData::checkRandom(bool& match, OBSWeakSource& scene, OBSWeakSource& transition, int& delay)
|
||||||
|
{
|
||||||
|
if (randomSwitches.size() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
vector<RandomSwitch> rs (randomSwitches);
|
||||||
|
std::random_device rng;
|
||||||
|
std::mt19937 urng(rng());
|
||||||
|
std::shuffle(rs.begin(), rs.end(), urng);
|
||||||
|
for (RandomSwitch& r : rs)
|
||||||
|
{
|
||||||
|
if (r.scene == lastRandomScene)
|
||||||
|
continue;
|
||||||
|
scene = r.scene;
|
||||||
|
transition = r.transition;
|
||||||
|
delay = (int)r.delay * 1000;
|
||||||
|
match = true;
|
||||||
|
lastRandomScene = r.scene;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,9 +2,7 @@
|
|||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
#include <obs.hpp>
|
#include <obs.hpp>
|
||||||
|
|
||||||
#include "advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
|
||||||
obs_weak_source_t* getNextTransition(obs_weak_source_t* scene1, obs_weak_source_t* scene2);
|
|
||||||
|
|
||||||
void SceneSwitcher::on_sceneRoundTripAdd_clicked()
|
void SceneSwitcher::on_sceneRoundTripAdd_clicked()
|
||||||
{
|
{
|
||||||
@@ -15,7 +13,7 @@ void SceneSwitcher::on_sceneRoundTripAdd_clicked()
|
|||||||
if (scene1Name.isEmpty() || scene2Name.isEmpty())
|
if (scene1Name.isEmpty() || scene2Name.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int delay = ui->sceneRoundTripSpinBox->value();
|
double delay = ui->sceneRoundTripSpinBox->value();
|
||||||
|
|
||||||
if (scene1Name == scene2Name)
|
if (scene1Name == scene2Name)
|
||||||
return;
|
return;
|
||||||
@@ -36,7 +34,9 @@ void SceneSwitcher::on_sceneRoundTripAdd_clicked()
|
|||||||
|
|
||||||
lock_guard<mutex> lock(switcher->m);
|
lock_guard<mutex> lock(switcher->m);
|
||||||
switcher->sceneRoundTripSwitches.emplace_back(
|
switcher->sceneRoundTripSwitches.emplace_back(
|
||||||
source1, source2, transition, delay, text.toUtf8().constData());
|
source1, source2, transition, int(delay * 1000),
|
||||||
|
(scene2Name == QString(PREVIOUS_SCENE_NAME)),
|
||||||
|
text.toUtf8().constData());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -47,10 +47,12 @@ void SceneSwitcher::on_sceneRoundTripAdd_clicked()
|
|||||||
lock_guard<mutex> lock(switcher->m);
|
lock_guard<mutex> lock(switcher->m);
|
||||||
for (auto& s : switcher->sceneRoundTripSwitches)
|
for (auto& s : switcher->sceneRoundTripSwitches)
|
||||||
{
|
{
|
||||||
if (s.scene1 == source1 && s.scene2 == source2)
|
if (s.scene1 == source1)
|
||||||
{
|
{
|
||||||
s.delay = delay;
|
s.scene2 = source2;
|
||||||
|
s.delay = int(delay * 1000);
|
||||||
s.transition = transition;
|
s.transition = transition;
|
||||||
|
s.usePreviousScene = (scene2Name == QString(PREVIOUS_SCENE_NAME));
|
||||||
s.sceneRoundTripStr = text.toUtf8().constData();
|
s.sceneRoundTripStr = text.toUtf8().constData();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -139,7 +141,10 @@ void SceneSwitcher::on_sceneRoundTripSave_clicked()
|
|||||||
for (SceneRoundTripSwitch s : switcher->sceneRoundTripSwitches)
|
for (SceneRoundTripSwitch s : switcher->sceneRoundTripSwitches)
|
||||||
{
|
{
|
||||||
out << QString::fromStdString(GetWeakSourceName(s.scene1)) << "\n";
|
out << QString::fromStdString(GetWeakSourceName(s.scene1)) << "\n";
|
||||||
out << QString::fromStdString(GetWeakSourceName(s.scene2)) << "\n";
|
if (s.usePreviousScene)
|
||||||
|
out << (PREVIOUS_SCENE_NAME) << "\n";
|
||||||
|
else
|
||||||
|
out << QString::fromStdString(GetWeakSourceName(s.scene2)) << "\n";
|
||||||
out << s.delay << "\n";
|
out << s.delay << "\n";
|
||||||
out << QString::fromStdString(s.sceneRoundTripStr) << "\n";
|
out << QString::fromStdString(s.sceneRoundTripStr) << "\n";
|
||||||
out << QString::fromStdString(GetWeakSourceName(s.transition)) << "\n";
|
out << QString::fromStdString(GetWeakSourceName(s.transition)) << "\n";
|
||||||
@@ -174,7 +179,7 @@ void SceneSwitcher::on_sceneRoundTripLoad_clicked()
|
|||||||
OBSWeakSource scene2 = GetWeakSourceByQString(lines[1]);
|
OBSWeakSource scene2 = GetWeakSourceByQString(lines[1]);
|
||||||
OBSWeakSource transition = GetWeakTransitionByQString(lines[4]);
|
OBSWeakSource transition = GetWeakTransitionByQString(lines[4]);
|
||||||
|
|
||||||
if (WeakSourceValid(scene1) && WeakSourceValid(scene2)
|
if (WeakSourceValid(scene1) && ((lines[1] == QString(PREVIOUS_SCENE_NAME)) || (WeakSourceValid(scene2)))
|
||||||
&& WeakSourceValid(transition))
|
&& WeakSourceValid(transition))
|
||||||
{
|
{
|
||||||
newSceneRoundTripSwitch.emplace_back(SceneRoundTripSwitch(
|
newSceneRoundTripSwitch.emplace_back(SceneRoundTripSwitch(
|
||||||
@@ -182,12 +187,13 @@ void SceneSwitcher::on_sceneRoundTripLoad_clicked()
|
|||||||
GetWeakSourceByQString(lines[1]),
|
GetWeakSourceByQString(lines[1]),
|
||||||
GetWeakTransitionByQString(lines[4]),
|
GetWeakTransitionByQString(lines[4]),
|
||||||
lines[2].toInt(),
|
lines[2].toInt(),
|
||||||
|
(lines[1] == QString(PREVIOUS_SCENE_NAME)),
|
||||||
lines[3].toStdString()));
|
lines[3].toStdString()));
|
||||||
}
|
}
|
||||||
lines.clear();
|
lines.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//unvalid amount of lines in file or nothing valid read
|
|
||||||
if (lines.size() != 0 || newSceneRoundTripSwitch.size() == 0)
|
if (lines.size() != 0 || newSceneRoundTripSwitch.size() == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -214,11 +220,10 @@ void SwitcherData::checkSceneRoundTrip(bool& match, OBSWeakSource& scene, OBSWea
|
|||||||
if (s.scene1 == ws)
|
if (s.scene1 == ws)
|
||||||
{
|
{
|
||||||
sceneRoundTripActive = true;
|
sceneRoundTripActive = true;
|
||||||
int dur = s.delay * 1000 - interval;
|
int dur = s.delay - interval;
|
||||||
if (dur > 0)
|
if (dur > 0)
|
||||||
{
|
{
|
||||||
string s = obs_source_get_name(currentSource);
|
waitScene = currentSource;
|
||||||
waitSceneName = s;
|
|
||||||
cv.wait_for(lock, chrono::milliseconds(dur));
|
cv.wait_for(lock, chrono::milliseconds(dur));
|
||||||
}
|
}
|
||||||
obs_source_t* currentSource2 = obs_frontend_get_current_scene();
|
obs_source_t* currentSource2 = obs_frontend_get_current_scene();
|
||||||
@@ -227,7 +232,7 @@ void SwitcherData::checkSceneRoundTrip(bool& match, OBSWeakSource& scene, OBSWea
|
|||||||
if (currentSource == currentSource2)
|
if (currentSource == currentSource2)
|
||||||
{
|
{
|
||||||
match = true;
|
match = true;
|
||||||
scene = s.scene2;
|
scene = (s.usePreviousScene) ? previousScene : s.scene2;
|
||||||
transition = s.transition;
|
transition = s.transition;
|
||||||
}
|
}
|
||||||
obs_source_release(currentSource2);
|
obs_source_release(currentSource2);
|
||||||
@@ -247,7 +252,7 @@ void SceneSwitcher::on_sceneRoundTrips_currentRowChanged(int idx)
|
|||||||
|
|
||||||
QListWidgetItem* item = ui->sceneRoundTrips->item(idx);
|
QListWidgetItem* item = ui->sceneRoundTrips->item(idx);
|
||||||
|
|
||||||
QString sceneRoundTrip = item->data(Qt::UserRole).toString();
|
QString sceneRoundTrip = item->text();
|
||||||
|
|
||||||
lock_guard<mutex> lock(switcher->m);
|
lock_guard<mutex> lock(switcher->m);
|
||||||
for (auto& s : switcher->sceneRoundTripSwitches)
|
for (auto& s : switcher->sceneRoundTripSwitches)
|
||||||
@@ -261,7 +266,7 @@ void SceneSwitcher::on_sceneRoundTrips_currentRowChanged(int idx)
|
|||||||
ui->sceneRoundTripScenes1->setCurrentText(scene1.c_str());
|
ui->sceneRoundTripScenes1->setCurrentText(scene1.c_str());
|
||||||
ui->sceneRoundTripScenes2->setCurrentText(scene2.c_str());
|
ui->sceneRoundTripScenes2->setCurrentText(scene2.c_str());
|
||||||
ui->sceneRoundTripTransitions->setCurrentText(transitionName.c_str());
|
ui->sceneRoundTripTransitions->setCurrentText(transitionName.c_str());
|
||||||
ui->sceneRoundTripSpinBox->setValue(delay);
|
ui->sceneRoundTripSpinBox->setValue((double)delay/1000);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -270,7 +275,7 @@ void SceneSwitcher::on_sceneRoundTrips_currentRowChanged(int idx)
|
|||||||
|
|
||||||
int SceneSwitcher::SceneRoundTripFindByData(const QString& scene1)
|
int SceneSwitcher::SceneRoundTripFindByData(const QString& scene1)
|
||||||
{
|
{
|
||||||
QRegExp rx(scene1 + " -> wait for [0-9]* seconds -> .*");
|
QRegExp rx(scene1 + " ->.*");
|
||||||
int count = ui->sceneRoundTrips->count();
|
int count = ui->sceneRoundTrips->count();
|
||||||
int idx = -1;
|
int idx = -1;
|
||||||
|
|
||||||
@@ -305,4 +310,3 @@ void SwitcherData::autoStopStreamAndRecording()
|
|||||||
obs_source_release(currentSource);
|
obs_source_release(currentSource);
|
||||||
obs_weak_source_release(ws);
|
obs_weak_source_release(ws);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
|
||||||
void SceneSwitcher::on_transitionsAdd_clicked()
|
void SceneSwitcher::on_transitionsAdd_clicked()
|
||||||
{
|
{
|
||||||
@@ -153,7 +153,7 @@ void SceneSwitcher::on_defaultTransitionsRemove_clicked()
|
|||||||
delete item;
|
delete item;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwitcherData::setDefaultSceneTransitions(unique_lock<mutex>& lock)
|
void SwitcherData::setDefaultSceneTransitions()
|
||||||
{
|
{
|
||||||
obs_source_t* currentSource = obs_frontend_get_current_scene();
|
obs_source_t* currentSource = obs_frontend_get_current_scene();
|
||||||
obs_weak_source_t* ws = obs_source_get_weak_source(currentSource);
|
obs_weak_source_t* ws = obs_source_get_weak_source(currentSource);
|
||||||
@@ -163,7 +163,8 @@ void SwitcherData::setDefaultSceneTransitions(unique_lock<mutex>& lock)
|
|||||||
if (s.scene == ws)
|
if (s.scene == ws)
|
||||||
{
|
{
|
||||||
obs_source_t* transition = obs_weak_source_get_source(s.transition);
|
obs_source_t* transition = obs_weak_source_get_source(s.transition);
|
||||||
//sleep planned but no fitting OBS event to measure transition time
|
//This might cancel the current transition
|
||||||
|
//There is no way to be sure when the previous transition finished
|
||||||
obs_frontend_set_current_transition(transition);
|
obs_frontend_set_current_transition(transition);
|
||||||
obs_source_release(transition);
|
obs_source_release(transition);
|
||||||
break;
|
break;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
|
||||||
void SwitcherData::checkScreenRegionSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
|
void SwitcherData::checkScreenRegionSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <util/platform.h>
|
#include <util/platform.h>
|
||||||
#include "advanced-scene-switcher.hpp"
|
#include "../headers/advanced-scene-switcher.hpp"
|
||||||
#include <TlHelp32.h>
|
#include <TlHelp32.h>
|
||||||
#include <Psapi.h>
|
#include <Psapi.h>
|
||||||
|
|
||||||
@@ -61,14 +61,15 @@ void GetWindowList(vector<string>& windows)
|
|||||||
void GetCurrentWindowTitle(string& title)
|
void GetCurrentWindowTitle(string& title)
|
||||||
{
|
{
|
||||||
HWND window = GetForegroundWindow();
|
HWND window = GetForegroundWindow();
|
||||||
DWORD id;
|
DWORD pid;
|
||||||
GetWindowThreadProcessId(window, &id);
|
DWORD thid;
|
||||||
|
thid = GetWindowThreadProcessId(window, &pid);
|
||||||
/*GetWindowText will freeze if the control it is reading was created in another thread.
|
/*GetWindowText will freeze if the control it is reading was created in another thread.
|
||||||
It does not directly read the control.Instead,
|
It does not directly read the control.Instead,
|
||||||
it waits for the thread that created the control to process a WM_GETTEXT message.
|
it waits for the thread that created the control to process a WM_GETTEXT message.
|
||||||
So if that thread is frozen in a WaitFor... call you have a deadlock.*/
|
So if that thread is frozen in a WaitFor... call you have a deadlock.*/
|
||||||
if (id == GetCurrentProcessId()) {
|
if (GetCurrentProcessId() == pid) {
|
||||||
title = "";
|
title = "OBS";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
GetWindowTitle(window, title);
|
GetWindowTitle(window, title);
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#include <obs-module.h>
|
#include <obs-module.h>
|
||||||
#include "advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
|
||||||
void SceneSwitcher::on_add_clicked()
|
void SceneSwitcher::on_add_clicked()
|
||||||
{
|
{
|
||||||
@@ -22,7 +22,7 @@ void SceneSwitcher::on_add_clicked()
|
|||||||
if (idx == -1)
|
if (idx == -1)
|
||||||
{
|
{
|
||||||
lock_guard<mutex> lock(switcher->m);
|
lock_guard<mutex> lock(switcher->m);
|
||||||
switcher->switches.emplace_back(
|
switcher->windowSwitches.emplace_back(
|
||||||
source, windowName.toUtf8().constData(), transition, fullscreen);
|
source, windowName.toUtf8().constData(), transition, fullscreen);
|
||||||
|
|
||||||
QListWidgetItem* item = new QListWidgetItem(text, ui->switches);
|
QListWidgetItem* item = new QListWidgetItem(text, ui->switches);
|
||||||
@@ -37,7 +37,7 @@ void SceneSwitcher::on_add_clicked()
|
|||||||
|
|
||||||
{
|
{
|
||||||
lock_guard<mutex> lock(switcher->m);
|
lock_guard<mutex> lock(switcher->m);
|
||||||
for (auto& s : switcher->switches)
|
for (auto& s : switcher->windowSwitches)
|
||||||
{
|
{
|
||||||
if (s.window == window)
|
if (s.window == window)
|
||||||
{
|
{
|
||||||
@@ -63,7 +63,7 @@ void SceneSwitcher::on_remove_clicked()
|
|||||||
|
|
||||||
{
|
{
|
||||||
lock_guard<mutex> lock(switcher->m);
|
lock_guard<mutex> lock(switcher->m);
|
||||||
auto& switches = switcher->switches;
|
auto& switches = switcher->windowSwitches;
|
||||||
|
|
||||||
for (auto it = switches.begin(); it != switches.end(); ++it)
|
for (auto it = switches.begin(); it != switches.end(); ++it)
|
||||||
{
|
{
|
||||||
@@ -188,7 +188,7 @@ void SceneSwitcher::on_switches_currentRowChanged(int idx)
|
|||||||
QString window = item->data(Qt::UserRole).toString();
|
QString window = item->data(Qt::UserRole).toString();
|
||||||
|
|
||||||
lock_guard<mutex> lock(switcher->m);
|
lock_guard<mutex> lock(switcher->m);
|
||||||
for (auto& s : switcher->switches)
|
for (auto& s : switcher->windowSwitches)
|
||||||
{
|
{
|
||||||
if (window.compare(s.window.c_str()) == 0)
|
if (window.compare(s.window.c_str()) == 0)
|
||||||
{
|
{
|
||||||
@@ -204,8 +204,6 @@ void SceneSwitcher::on_switches_currentRowChanged(int idx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void SceneSwitcher::on_ignoreWindows_currentRowChanged(int idx)
|
void SceneSwitcher::on_ignoreWindows_currentRowChanged(int idx)
|
||||||
{
|
{
|
||||||
if (loading)
|
if (loading)
|
||||||
@@ -235,16 +233,23 @@ void SwitcherData::checkWindowTitleSwitch(bool& match, OBSWeakSource& scene, OBS
|
|||||||
GetCurrentWindowTitle(title);
|
GetCurrentWindowTitle(title);
|
||||||
for (auto& window : ignoreWindowsSwitches)
|
for (auto& window : ignoreWindowsSwitches)
|
||||||
{
|
{
|
||||||
if (window == title)
|
try
|
||||||
|
{
|
||||||
|
bool matches = regex_match(title, regex(window));
|
||||||
|
if (matches)
|
||||||
|
{
|
||||||
|
title = lastTitle;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const regex_error&)
|
||||||
{
|
{
|
||||||
title = lastTitle;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lastTitle = title;
|
lastTitle = title;
|
||||||
|
|
||||||
//direct match
|
//direct match
|
||||||
for (SceneSwitch& s : switches)
|
for (WindowSceneSwitch& s : windowSwitches)
|
||||||
{
|
{
|
||||||
if (s.window == title)
|
if (s.window == title)
|
||||||
{
|
{
|
||||||
@@ -255,7 +260,7 @@ void SwitcherData::checkWindowTitleSwitch(bool& match, OBSWeakSource& scene, OBS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//regex match
|
//regex match
|
||||||
for (SceneSwitch& s : switches)
|
for (WindowSceneSwitch& s : windowSwitches)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -273,4 +278,3 @@ void SwitcherData::checkWindowTitleSwitch(bool& match, OBSWeakSource& scene, OBS
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,288 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <condition_variable>
|
|
||||||
#include <chrono>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <thread>
|
|
||||||
#include <regex>
|
|
||||||
#include <mutex>
|
|
||||||
#include <fstream>
|
|
||||||
#include "utility.hpp"
|
|
||||||
|
|
||||||
#define DEFAULT_INTERVAL 300
|
|
||||||
|
|
||||||
#define READ_FILE_FUNC "File based"
|
|
||||||
#define ROUND_TRIP_FUNC "Scene Sequence"
|
|
||||||
#define IDLE_FUNC "Idle detection"
|
|
||||||
#define EXE_FUNC "Executable"
|
|
||||||
#define SCREEN_REGION_FUNC "Screen region"
|
|
||||||
#define WINDOW_TITLE_FUNC "Window title"
|
|
||||||
|
|
||||||
#define DEFAULT_PRIORITY_0 READ_FILE_FUNC
|
|
||||||
#define DEFAULT_PRIORITY_1 ROUND_TRIP_FUNC
|
|
||||||
#define DEFAULT_PRIORITY_2 IDLE_FUNC
|
|
||||||
#define DEFAULT_PRIORITY_3 EXE_FUNC
|
|
||||||
#define DEFAULT_PRIORITY_4 SCREEN_REGION_FUNC
|
|
||||||
#define DEFAULT_PRIORITY_5 WINDOW_TITLE_FUNC
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
struct SceneSwitch
|
|
||||||
{
|
|
||||||
OBSWeakSource scene;
|
|
||||||
string window;
|
|
||||||
OBSWeakSource transition;
|
|
||||||
bool fullscreen;
|
|
||||||
|
|
||||||
inline SceneSwitch(
|
|
||||||
OBSWeakSource scene_, const char* window_, OBSWeakSource transition_, bool fullscreen_)
|
|
||||||
: scene(scene_)
|
|
||||||
, window(window_)
|
|
||||||
, transition(transition_)
|
|
||||||
, fullscreen(fullscreen_)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ExecutableSceneSwitch
|
|
||||||
{
|
|
||||||
OBSWeakSource mScene;
|
|
||||||
OBSWeakSource mTransition;
|
|
||||||
QString mExe;
|
|
||||||
bool mInFocus;
|
|
||||||
|
|
||||||
inline ExecutableSceneSwitch(
|
|
||||||
OBSWeakSource scene, OBSWeakSource transition, const QString& exe, bool inFocus)
|
|
||||||
: mScene(scene)
|
|
||||||
, mTransition(transition)
|
|
||||||
, mExe(exe)
|
|
||||||
, mInFocus(inFocus)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ScreenRegionSwitch
|
|
||||||
{
|
|
||||||
OBSWeakSource scene;
|
|
||||||
OBSWeakSource transition;
|
|
||||||
int minX, minY, maxX, maxY;
|
|
||||||
string regionStr;
|
|
||||||
|
|
||||||
inline ScreenRegionSwitch(OBSWeakSource scene_, OBSWeakSource transition_, int minX_, int minY_,
|
|
||||||
int maxX_, int maxY_, string regionStr_)
|
|
||||||
: scene(scene_)
|
|
||||||
, transition(transition_)
|
|
||||||
, minX(minX_)
|
|
||||||
, minY(minY_)
|
|
||||||
, maxX(maxX_)
|
|
||||||
, maxY(maxY_)
|
|
||||||
, regionStr(regionStr_)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SceneRoundTripSwitch
|
|
||||||
{
|
|
||||||
OBSWeakSource scene1;
|
|
||||||
OBSWeakSource scene2;
|
|
||||||
OBSWeakSource transition;
|
|
||||||
int delay;
|
|
||||||
string sceneRoundTripStr;
|
|
||||||
|
|
||||||
inline SceneRoundTripSwitch(OBSWeakSource scene1_, OBSWeakSource scene2_,
|
|
||||||
OBSWeakSource transition_, int delay_, string str)
|
|
||||||
: scene1(scene1_)
|
|
||||||
, scene2(scene2_)
|
|
||||||
, transition(transition_)
|
|
||||||
, delay(delay_)
|
|
||||||
, sceneRoundTripStr(str)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SceneTransition
|
|
||||||
{
|
|
||||||
OBSWeakSource scene1;
|
|
||||||
OBSWeakSource scene2;
|
|
||||||
OBSWeakSource transition;
|
|
||||||
string sceneTransitionStr;
|
|
||||||
|
|
||||||
inline SceneTransition(OBSWeakSource scene1_, OBSWeakSource scene2_, OBSWeakSource transition_,
|
|
||||||
string sceneTransitionStr_)
|
|
||||||
: scene1(scene1_)
|
|
||||||
, scene2(scene2_)
|
|
||||||
, transition(transition_)
|
|
||||||
, sceneTransitionStr(sceneTransitionStr_)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DefaultSceneTransition
|
|
||||||
{
|
|
||||||
OBSWeakSource scene;
|
|
||||||
OBSWeakSource transition;
|
|
||||||
string sceneTransitionStr;
|
|
||||||
|
|
||||||
inline DefaultSceneTransition(OBSWeakSource scene_, OBSWeakSource transition_,
|
|
||||||
string sceneTransitionStr_)
|
|
||||||
: scene(scene_)
|
|
||||||
, transition(transition_)
|
|
||||||
, sceneTransitionStr(sceneTransitionStr_)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FileIOData
|
|
||||||
{
|
|
||||||
bool readEnabled;
|
|
||||||
string readPath;
|
|
||||||
bool writeEnabled;
|
|
||||||
string writePath;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct IdleData
|
|
||||||
{
|
|
||||||
bool idleEnable;
|
|
||||||
int time;
|
|
||||||
OBSWeakSource scene;
|
|
||||||
OBSWeakSource transition;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct SwitcherData
|
|
||||||
{
|
|
||||||
thread th;
|
|
||||||
condition_variable cv;
|
|
||||||
mutex m;
|
|
||||||
mutex transitionMutex;
|
|
||||||
bool transitionActive = false;
|
|
||||||
bool waitForTransition = false;
|
|
||||||
condition_variable transitionCv;
|
|
||||||
bool stop = false;
|
|
||||||
|
|
||||||
vector<SceneSwitch> switches;
|
|
||||||
string lastTitle;
|
|
||||||
OBSWeakSource nonMatchingScene;
|
|
||||||
int interval = DEFAULT_INTERVAL;
|
|
||||||
bool switchIfNotMatching = false;
|
|
||||||
bool startAtLaunch = false;
|
|
||||||
vector<ScreenRegionSwitch> screenRegionSwitches;
|
|
||||||
vector<OBSWeakSource> pauseScenesSwitches;
|
|
||||||
vector<string> pauseWindowsSwitches;
|
|
||||||
vector<string> ignoreWindowsSwitches;
|
|
||||||
vector<SceneRoundTripSwitch> sceneRoundTripSwitches;
|
|
||||||
bool autoStopEnable = false;
|
|
||||||
OBSWeakSource autoStopScene;
|
|
||||||
string waitSceneName; //indicates which scene was active when we startet waiting on something
|
|
||||||
vector<SceneTransition> sceneTransitions;
|
|
||||||
vector<DefaultSceneTransition> defaultSceneTransitions;
|
|
||||||
vector<ExecutableSceneSwitch> executableSwitches;
|
|
||||||
FileIOData fileIO;
|
|
||||||
IdleData idleData;
|
|
||||||
vector<string> ignoreIdleWindows;
|
|
||||||
vector<string> functionNamesByPriority = vector<string>{
|
|
||||||
string(DEFAULT_PRIORITY_0),
|
|
||||||
string(DEFAULT_PRIORITY_1),
|
|
||||||
string(DEFAULT_PRIORITY_2),
|
|
||||||
string(DEFAULT_PRIORITY_3),
|
|
||||||
string(DEFAULT_PRIORITY_4),
|
|
||||||
string(DEFAULT_PRIORITY_5),
|
|
||||||
};
|
|
||||||
|
|
||||||
void Thread();
|
|
||||||
void Start();
|
|
||||||
void Stop();
|
|
||||||
|
|
||||||
bool sceneChangedDuringWait();
|
|
||||||
bool prioFuncsValid();
|
|
||||||
void writeSceneInfoToFile();
|
|
||||||
void setDefaultSceneTransitions(unique_lock<mutex>& lock);
|
|
||||||
void autoStopStreamAndRecording();
|
|
||||||
bool checkPause();
|
|
||||||
void checkSceneRoundTrip(bool& match, OBSWeakSource& scene, OBSWeakSource& transition, unique_lock<mutex>& lock);
|
|
||||||
void checkIdleSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition);
|
|
||||||
void checkWindowTitleSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition);
|
|
||||||
void checkExeSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition);
|
|
||||||
void checkScreenRegionSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition);
|
|
||||||
void checkSwitchInfoFromFile(bool& match, OBSWeakSource& scene, OBSWeakSource& transition);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Prune()
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < switches.size(); i++)
|
|
||||||
{
|
|
||||||
SceneSwitch& s = switches[i];
|
|
||||||
if (!WeakSourceValid(s.scene) || !WeakSourceValid(s.transition))
|
|
||||||
switches.erase(switches.begin() + i--);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nonMatchingScene && !WeakSourceValid(nonMatchingScene))
|
|
||||||
{
|
|
||||||
switchIfNotMatching = false;
|
|
||||||
nonMatchingScene = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < screenRegionSwitches.size(); i++)
|
|
||||||
{
|
|
||||||
ScreenRegionSwitch& s = screenRegionSwitches[i];
|
|
||||||
if (!WeakSourceValid(s.scene) || !WeakSourceValid(s.transition))
|
|
||||||
screenRegionSwitches.erase(screenRegionSwitches.begin() + i--);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < pauseScenesSwitches.size(); i++)
|
|
||||||
{
|
|
||||||
OBSWeakSource& scene = pauseScenesSwitches[i];
|
|
||||||
if (!WeakSourceValid(scene))
|
|
||||||
pauseScenesSwitches.erase(pauseScenesSwitches.begin() + i--);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < sceneRoundTripSwitches.size(); i++)
|
|
||||||
{
|
|
||||||
SceneRoundTripSwitch& s = sceneRoundTripSwitches[i];
|
|
||||||
if (!WeakSourceValid(s.scene1) || !WeakSourceValid(s.scene2)
|
|
||||||
|| !WeakSourceValid(s.transition))
|
|
||||||
sceneRoundTripSwitches.erase(sceneRoundTripSwitches.begin() + i--);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!WeakSourceValid(autoStopScene))
|
|
||||||
{
|
|
||||||
autoStopScene = nullptr;
|
|
||||||
autoStopEnable = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < sceneTransitions.size(); i++)
|
|
||||||
{
|
|
||||||
SceneTransition& s = sceneTransitions[i];
|
|
||||||
if (!WeakSourceValid(s.scene1) || !WeakSourceValid(s.scene2)
|
|
||||||
|| !WeakSourceValid(s.transition))
|
|
||||||
sceneTransitions.erase(sceneTransitions.begin() + i--);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < defaultSceneTransitions.size(); i++)
|
|
||||||
{
|
|
||||||
DefaultSceneTransition& s = defaultSceneTransitions[i];
|
|
||||||
if (!WeakSourceValid(s.scene) || !WeakSourceValid(s.transition))
|
|
||||||
defaultSceneTransitions.erase(defaultSceneTransitions.begin() + i--);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < executableSwitches.size(); i++)
|
|
||||||
{
|
|
||||||
ExecutableSceneSwitch& s = executableSwitches[i];
|
|
||||||
if (!WeakSourceValid(s.mScene) || !WeakSourceValid(s.mTransition))
|
|
||||||
executableSwitches.erase(executableSwitches.begin() + i--);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!WeakSourceValid(idleData.scene) || !WeakSourceValid(idleData.transition))
|
|
||||||
{
|
|
||||||
idleData.idleEnable = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
inline ~SwitcherData()
|
|
||||||
{
|
|
||||||
Stop();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
140
utility.hpp
140
utility.hpp
@@ -1,140 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <obs.hpp>
|
|
||||||
#include <QString>
|
|
||||||
#include <obs-frontend-api.h>
|
|
||||||
#include "switcher-data-structs.hpp"
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
static inline bool WeakSourceValid(obs_weak_source_t* ws)
|
|
||||||
{
|
|
||||||
obs_source_t* source = obs_weak_source_get_source(ws);
|
|
||||||
if (source)
|
|
||||||
obs_source_release(source);
|
|
||||||
return !!source;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline QString MakeSwitchName(
|
|
||||||
const QString& scene, const QString& value, const QString& transition, bool fullscreen)
|
|
||||||
{
|
|
||||||
if (!fullscreen)
|
|
||||||
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition
|
|
||||||
+ QStringLiteral("]: ") + value;
|
|
||||||
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition + QStringLiteral("]: ")
|
|
||||||
+ value + QStringLiteral(" (only if window is fullscreen)");
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline QString MakeSwitchNameExecutable(
|
|
||||||
const QString& scene, const QString& value, const QString& transition, bool inFocus)
|
|
||||||
{
|
|
||||||
if (!inFocus)
|
|
||||||
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition
|
|
||||||
+ QStringLiteral("]: ") + value;
|
|
||||||
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition + QStringLiteral("]: ")
|
|
||||||
+ value + QStringLiteral(" (only if window is focused)");
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline QString MakeScreenRegionSwitchName(
|
|
||||||
const QString& scene, const QString& transition, int minX, int minY, int maxX, int maxY)
|
|
||||||
{
|
|
||||||
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition + QStringLiteral("]: ")
|
|
||||||
+ QString::number(minX) + QStringLiteral(", ") + QString::number(minY)
|
|
||||||
+ QStringLiteral(" x ") + QString::number(maxX) + QStringLiteral(", ")
|
|
||||||
+ QString::number(maxY);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline QString MakeSceneRoundTripSwitchName(
|
|
||||||
const QString& scene1, const QString& scene2, const QString& transition, int delay)
|
|
||||||
{
|
|
||||||
return scene1 + QStringLiteral(" -> wait for ") + QString::number(delay)
|
|
||||||
+ QStringLiteral(" seconds -> ") + scene2 + QStringLiteral(" (using ") + transition
|
|
||||||
+ QStringLiteral(" transition)");
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline QString MakeSceneTransitionName(
|
|
||||||
const QString& scene1, const QString& scene2, const QString& transition)
|
|
||||||
{
|
|
||||||
return scene1 + QStringLiteral(" --- ") + transition + QStringLiteral(" --> ") + scene2;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline QString MakeDefaultSceneTransitionName(
|
|
||||||
const QString& scene, const QString& transition)
|
|
||||||
{
|
|
||||||
return scene + QStringLiteral(" --> ") + transition;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline string GetWeakSourceName(obs_weak_source_t* weak_source)
|
|
||||||
{
|
|
||||||
string name;
|
|
||||||
|
|
||||||
obs_source_t* source = obs_weak_source_get_source(weak_source);
|
|
||||||
if (source)
|
|
||||||
{
|
|
||||||
name = obs_source_get_name(source);
|
|
||||||
obs_source_release(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline OBSWeakSource GetWeakSourceByName(const char* name)
|
|
||||||
{
|
|
||||||
OBSWeakSource weak;
|
|
||||||
obs_source_t* source = obs_get_source_by_name(name);
|
|
||||||
if (source)
|
|
||||||
{
|
|
||||||
weak = obs_source_get_weak_source(source);
|
|
||||||
obs_weak_source_release(weak);
|
|
||||||
obs_source_release(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
return weak;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline OBSWeakSource GetWeakSourceByQString(const QString& name)
|
|
||||||
{
|
|
||||||
return GetWeakSourceByName(name.toUtf8().constData());
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline OBSWeakSource GetWeakTransitionByName(const char* transitionName)
|
|
||||||
{
|
|
||||||
OBSWeakSource weak;
|
|
||||||
obs_source_t* source = nullptr;
|
|
||||||
|
|
||||||
if (strcmp(transitionName, "Default") == 0)
|
|
||||||
{
|
|
||||||
source = obs_frontend_get_current_transition();
|
|
||||||
weak = obs_source_get_weak_source(source);
|
|
||||||
obs_source_release(source);
|
|
||||||
obs_weak_source_release(weak);
|
|
||||||
return weak;
|
|
||||||
}
|
|
||||||
|
|
||||||
obs_frontend_source_list* transitions = new obs_frontend_source_list();
|
|
||||||
obs_frontend_get_transitions(transitions);
|
|
||||||
bool match = false;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < transitions->sources.num; i++)
|
|
||||||
{
|
|
||||||
const char* name = obs_source_get_name(transitions->sources.array[i]);
|
|
||||||
if (strcmp(transitionName, name) == 0)
|
|
||||||
{
|
|
||||||
match = true;
|
|
||||||
source = transitions->sources.array[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (match){
|
|
||||||
weak = obs_source_get_weak_source(source);
|
|
||||||
obs_weak_source_release(weak);
|
|
||||||
}
|
|
||||||
obs_frontend_source_list_free(transitions);
|
|
||||||
|
|
||||||
return weak;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline OBSWeakSource GetWeakTransitionByQString(const QString& name)
|
|
||||||
{
|
|
||||||
return GetWeakTransitionByName(name.toUtf8().constData());
|
|
||||||
}
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user