diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 00000000..55d30267
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,284 @@
+name: build obs plugin
+
+on:
+ push:
+ branches: [ master ]
+ pull_request:
+ branches: [ master ]
+
+env:
+ PLUGIN_NAME: SceneSwitcher
+ LIB_NAME: advanced-scene-switcher
+
+jobs:
+ macos64:
+ name: "macOS 64-bit"
+ runs-on: [macos-latest]
+ env:
+ QT_VERSION: 5.14.1
+ OSX_DEPS_VERSION: '2020-04-07'
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+ with:
+ repository: obsproject/obs-studio
+ submodules: 'recursive'
+ - name: "Checkout plugin"
+ uses: actions/checkout@v2
+ with:
+ path: UI/frontend-plugins/${{ env.PLUGIN_NAME }}
+ - name: Fetch Git Tags
+ run: |
+ cd UI/frontend-plugins/${{ env.PLUGIN_NAME }}
+ git fetch --prune --tags --unshallow
+ - name: 'Install prerequisites (Homebrew)'
+ shell: bash
+ run: |
+ cd UI/frontend-plugins/${{ env.PLUGIN_NAME }}/CI/macos
+ brew bundle
+ cd -
+ - name: 'Install prerequisite: Pre-built dependencies'
+ shell: bash
+ run: |
+ curl -L -O https://github.com/obsproject/obs-deps/releases/download/${{ env.OSX_DEPS_VERSION }}/osx-deps-${{ env.OSX_DEPS_VERSION }}.tar.gz
+ tar -xf ./osx-deps-${{ env.OSX_DEPS_VERSION }}.tar.gz -C "/tmp"
+ - name: Configure
+ shell: bash
+ run: |
+ echo "add_subdirectory(${{ env.PLUGIN_NAME }})" >> UI/frontend-plugins/CMakeLists.txt
+ mkdir ./build
+ cd ./build
+ cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.11 -DDepsPath="/tmp/obsdeps" -DQTDIR="/usr/local/Cellar/qt/${{ env.QT_VERSION }}" ..
+ cd -
+ - name: Build
+ shell: bash
+ run: |
+ set -e
+ cd ./build
+ make -j4
+ cd -
+ - name: 'Install prerequisite: Packages app'
+ if: success()
+ shell: bash
+ run: |
+ curl -L -O https://s3-us-west-2.amazonaws.com/obs-nightly/Packages.pkg
+ sudo installer -pkg ./Packages.pkg -target /
+ - name: Package
+ if: success()
+ shell: bash
+ run: |
+ cd UI/frontend-plugins/${{ env.PLUGIN_NAME }}
+ install_name_tool -change @rpath/libobs-frontend-api.dylib @executable_path/../Frameworks/libobs-frontend-api.dylib ../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
+ install_name_tool -change @rpath/libobs.0.dylib @executable_path/../Frameworks/libobs.0.dylib ../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
+ install_name_tool -change /usr/local/opt/qt5/lib/QtWidgets.framework/Versions/5/QtWidgets @executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets ../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
+ install_name_tool -change /usr/local/opt/qt5/lib/QtGui.framework/Versions/5/QtGui @executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui ../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
+ install_name_tool -change /usr/local/opt/qt5/lib/QtCore.framework/Versions/5/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore ../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
+ FILE_DATE=$(date +%Y-%m-%d)
+ FILE_NAME=${{ env.PLUGIN_NAME }}-$FILE_DATE-${{ github.sha }}-macos.pkg
+ echo "::set-env name=FILE_NAME::${FILE_NAME}"
+ packagesbuild ./CI/macos/${{ env.PLUGIN_NAME }}.pkgproj
+ cd -
+ mkdir ./nightly
+ mv UI/frontend-plugins/${{ env.PLUGIN_NAME }}/${{ env.PLUGIN_NAME }}.pkg ./nightly/${FILE_NAME}
+ - name: Publish
+ if: success()
+ uses: actions/upload-artifact@v2-preview
+ with:
+ name: '${{ env.FILE_NAME }}'
+ path: ./nightly/*.pkg
+ ubuntu64:
+ name: 'Linux/Ubuntu 64-bit'
+ runs-on: [ubuntu-latest]
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+ with:
+ repository: obsproject/obs-studio
+ submodules: 'recursive'
+ - name: "Checkout plugin"
+ uses: actions/checkout@v2
+ with:
+ path: UI/frontend-plugins/${{ env.PLUGIN_NAME }}
+ - name: Add plugin to obs cmake
+ shell: bash
+ run: echo "add_subdirectory(${{ env.PLUGIN_NAME }})" >> UI/frontend-plugins/CMakeLists.txt
+ - name: Fetch Git Tags
+ run: git fetch --prune --tags --unshallow
+ - name: Install prerequisites (Apt)
+ shell: bash
+ run: |
+ sudo dpkg --add-architecture amd64
+ sudo apt-get -qq update
+ sudo apt-get install -y \
+ build-essential \
+ checkinstall \
+ cmake \
+ libasound2-dev \
+ libavcodec-dev \
+ libavdevice-dev \
+ libavfilter-dev \
+ libavformat-dev \
+ libavutil-dev \
+ libcurl4-openssl-dev \
+ libfdk-aac-dev \
+ libfontconfig-dev \
+ libfreetype6-dev \
+ libgl1-mesa-dev \
+ libjack-jackd2-dev \
+ libjansson-dev \
+ libluajit-5.1-dev \
+ libpulse-dev \
+ libqt5x11extras5-dev \
+ libspeexdsp-dev \
+ libswresample-dev \
+ libswscale-dev \
+ libudev-dev \
+ libv4l-dev \
+ libva-dev \
+ libvlc-dev \
+ libx11-dev \
+ libx264-dev \
+ libxcb-randr0-dev \
+ libxcb-shm0-dev \
+ libxcb-xinerama0-dev \
+ libxcomposite-dev \
+ libxinerama-dev \
+ libmbedtls-dev \
+ pkg-config \
+ python3-dev \
+ qtbase5-dev \
+ libqt5svg5-dev \
+ swig \
+ libxss-dev
+ - name: 'Configure'
+ shell: bash
+ run: |
+ mkdir ./build
+ cd ./build
+ cmake -DUNIX_STRUCTURE=0 -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}/obs-studio-portable" -DBUILD_CAPTIONS=OFF -DWITH_RTMPS=OFF -DBUILD_BROWSER=OFF ..
+ - name: 'Build'
+ shell: bash
+ working-directory: ${{ github.workspace }}/build
+ run: make -j4
+ - name: 'Package'
+ shell: bash
+ run: |
+ FILE_DATE=$(date +%Y-%m-%d)
+ FILE_NAME=${{ env.PLUGIN_NAME }}-$FILE_DATE-${{ github.sha }}-linux64.tar.gz
+ echo "::set-env name=FILE_NAME::${FILE_NAME}"
+ mkdir -p ./${{ env.PLUGIN_NAME }}/bin/64bit/
+ mv ./build/UI/frontend-plugins/${{ env.PLUGIN_NAME }}/${{ env.LIB_NAME }}.so ./${{ env.PLUGIN_NAME }}/bin/64bit/${{ env.LIB_NAME }}.so
+ tar -cvzf "${FILE_NAME}" ${{ env.PLUGIN_NAME }}
+ - name: 'Publish'
+ uses: actions/upload-artifact@v2-preview
+ with:
+ name: '${{ env.FILE_NAME }}'
+ path: '*.tar.gz'
+ win64:
+ name: Windows 64-bit
+ runs-on: [windows-latest]
+ env:
+ QT_VERSION: 5.10.1
+ CMAKE_GENERATOR: "Visual Studio 16 2019"
+ CMAKE_SYSTEM_VERSION: "10.0.18363.657"
+ steps:
+ - name: Add msbuild to PATH
+ uses: microsoft/setup-msbuild@v1.0.0
+ - name: Checkout obs
+ uses: actions/checkout@v2
+ with:
+ repository: obsproject/obs-studio
+ submodules: 'recursive'
+ - name: Checkout plugin
+ uses: actions/checkout@v2
+ with:
+ path: UI/frontend-plugins/${{ env.PLUGIN_NAME}}
+ - name: Add plugin to obs cmake
+ shell: cmd
+ run: echo add_subdirectory(${{ env.PLUGIN_NAME }}) >> UI/frontend-plugins/CMakeLists.txt
+ - name: Fetch Git Tags
+ run: git fetch --prune --tags --unshallow
+ - name: 'Install prerequisite: QT'
+ run: |
+ curl -kLO https://cdn-fastly.obsproject.com/downloads/Qt_${{ env.QT_VERSION }}.7z -f --retry 5 -C -
+ 7z x Qt_${{ env.QT_VERSION }}.7z -o"${{ github.workspace }}/cmbuild/QT"
+ - name: 'Install prerequisite: Pre-built dependencies'
+ run: |
+ curl -kLO https://cdn-fastly.obsproject.com/downloads/dependencies2017.zip -f --retry 5 -C -
+ 7z x dependencies2017.zip -o"${{ github.workspace }}/cmbuild/deps"
+ - name: Configure
+ run: |
+ mkdir ./build
+ mkdir ./build64
+ cd ./build64
+ cmake -G"${{ env.CMAKE_GENERATOR }}" -A"x64" -DCMAKE_SYSTEM_VERSION="${{ env.CMAKE_SYSTEM_VERSION }}" -DBUILD_BROWSER=false -DBUILD_CAPTIONS=false -DCOMPILE_D3D12_HOOK=false -DDepsPath="${{ github.workspace }}/cmbuild/deps/win64" -DQTDIR="${{ github.workspace }}/cmbuild/QT/${{ env.QT_VERSION }}/msvc2017_64" -DCOPIED_DEPENDENCIES=FALSE -DCOPY_DEPENDENCIES=TRUE ..
+ - name: Build
+ run: msbuild /m /p:Configuration=RelWithDebInfo .\build64\obs-studio.sln
+ - name: Package
+ if: success()
+ run: |
+ $env:FILE_DATE=(Get-Date -UFormat "%F")
+ $env:FILE_NAME="${{ env.PLUGIN_NAME }}-${env:FILE_DATE}-${{ github.sha }}-win64.zip"
+ echo "::set-env name=FILE_NAME::${env:FILE_NAME}"
+ robocopy .\build64\rundir\RelWithDebInfo\obs-plugins\64bit\ .\build\obs-plugins\64bit ${{ env.LIB_NAME }}.* /E /XF .gitignore
+ 7z a ${env:FILE_NAME} .\build\*
+ - name: Publish
+ if: success()
+ uses: actions/upload-artifact@v2-preview
+ with:
+ name: '${{ env.FILE_NAME }}'
+ path: '*-win64.zip'
+ win32:
+ name: Windows 32-bit
+ runs-on: [windows-latest]
+ env:
+ QT_VERSION: 5.10.1
+ CMAKE_GENERATOR: "Visual Studio 16 2019"
+ CMAKE_SYSTEM_VERSION: "10.0.18363.657"
+ steps:
+ - name: Add msbuild to PATH
+ uses: microsoft/setup-msbuild@v1.0.0
+ - name: Checkout obs
+ uses: actions/checkout@v2
+ with:
+ repository: obsproject/obs-studio
+ submodules: 'recursive'
+ - name: Checkout plugin
+ uses: actions/checkout@v2
+ with:
+ path: UI/frontend-plugins/${{ env.PLUGIN_NAME }}
+ - name: Add plugin to obs cmake
+ shell: cmd
+ run: echo add_subdirectory(${{ env.PLUGIN_NAME }}) >> UI/frontend-plugins/CMakeLists.txt
+ - name: Fetch Git Tags
+ run: git fetch --prune --tags --unshallow
+ - name: 'Install prerequisite: QT'
+ run: |
+ curl -kLO https://cdn-fastly.obsproject.com/downloads/Qt_${{ env.QT_VERSION }}.7z -f --retry 5 -C -
+ 7z x Qt_${{ env.QT_VERSION }}.7z -o"${{ github.workspace }}/cmbuild/QT"
+ - name: 'Install prerequisite: Pre-built dependencies'
+ run: |
+ curl -kLO https://cdn-fastly.obsproject.com/downloads/dependencies2017.zip -f --retry 5 -C -
+ 7z x dependencies2017.zip -o"${{ github.workspace }}/cmbuild/deps"
+ - name: Configure
+ run: |
+ mkdir ./build
+ mkdir ./build32
+ cd ./build32
+ cmake -G"${{ env.CMAKE_GENERATOR }}" -A"Win32" -DCMAKE_SYSTEM_VERSION="${{ env.CMAKE_SYSTEM_VERSION }}" -DBUILD_BROWSER=false -DBUILD_CAPTIONS=false -DCOMPILE_D3D12_HOOK=false -DDepsPath="${{ github.workspace }}/cmbuild/deps/win32" -DQTDIR="${{ github.workspace }}/cmbuild/QT/${{ env.QT_VERSION }}/msvc2017" -DCOPIED_DEPENDENCIES=FALSE -DCOPY_DEPENDENCIES=TRUE ..
+ - name: Build
+ run: msbuild /m /p:Configuration=RelWithDebInfo .\build32\obs-studio.sln
+ - name: Package
+ if: success()
+ run: |
+ $env:FILE_DATE=(Get-Date -UFormat "%F")
+ $env:FILE_NAME="${{ env.PLUGIN_NAME }}-${env:FILE_DATE}-${{ github.sha }}-win32.zip"
+ echo "::set-env name=FILE_NAME::${env:FILE_NAME}"
+ robocopy .\build32\rundir\RelWithDebInfo\obs-plugins\32bit\ .\build\obs-plugins\32bit ${{ env.LIB_NAME }}.* /E /XF .gitignore
+ 7z a ${env:FILE_NAME} .\build\*
+ - name: Publish
+ if: success()
+ uses: actions/upload-artifact@v2-preview
+ with:
+ name: '${{ env.FILE_NAME }}'
+ path: '*-win32.zip'
diff --git a/CI/macos/Brewfile b/CI/macos/Brewfile
new file mode 100644
index 00000000..1c081c25
--- /dev/null
+++ b/CI/macos/Brewfile
@@ -0,0 +1,6 @@
+brew "jack"
+brew "speexdsp"
+brew "cmake"
+brew "freetype"
+brew "fdk-aac"
+brew "https://gist.githubusercontent.com/DDRBoxman/9c7a2b08933166f4b61ed9a44b242609/raw/ef4de6c587c6bd7f50210eccd5bd51ff08e6de13/qt.rb"
\ No newline at end of file
diff --git a/CI/macos/SceneSwitcher.pkgproj b/CI/macos/SceneSwitcher.pkgproj
new file mode 100644
index 00000000..7cf80900
--- /dev/null
+++ b/CI/macos/SceneSwitcher.pkgproj
@@ -0,0 +1,760 @@
+
+
+
+
+ PROJECT
+
+ PACKAGE_FILES
+
+ DEFAULT_INSTALL_LOCATION
+ /
+ HIERARCHY
+
+ CHILDREN
+
+
+ CHILDREN
+
+
+ CHILDREN
+
+
+ CHILDREN
+
+
+ CHILDREN
+
+
+ CHILDREN
+
+
+ CHILDREN
+
+
+ CHILDREN
+
+ GID
+ 80
+ PATH
+ ../../../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
+ PATH_TYPE
+ 3
+ PERMISSIONS
+ 493
+ TYPE
+ 3
+ UID
+ 0
+
+
+ GID
+ 80
+ PATH
+ bin
+ PATH_TYPE
+ 0
+ PERMISSIONS
+ 493
+ TYPE
+ 2
+ UID
+ 0
+
+
+ GID
+ 80
+ PATH
+ advanced-scene-switcher
+ PATH_TYPE
+ 0
+ PERMISSIONS
+ 493
+ TYPE
+ 2
+ UID
+ 0
+
+
+ GID
+ 80
+ PATH
+ plugins
+ PATH_TYPE
+ 0
+ PERMISSIONS
+ 493
+ TYPE
+ 2
+ UID
+ 0
+
+
+ GID
+ 80
+ PATH
+ obs-studio
+ PATH_TYPE
+ 0
+ PERMISSIONS
+ 493
+ TYPE
+ 2
+ UID
+ 0
+
+
+ GID
+ 80
+ PATH
+ Application Support
+ PATH_TYPE
+ 0
+ PERMISSIONS
+ 493
+ TYPE
+ 1
+ UID
+ 0
+
+
+ CHILDREN
+
+ GID
+ 0
+ PATH
+ Automator
+ PATH_TYPE
+ 0
+ PERMISSIONS
+ 493
+ TYPE
+ 1
+ UID
+ 0
+
+
+ CHILDREN
+
+ GID
+ 0
+ PATH
+ Documentation
+ PATH_TYPE
+ 0
+ PERMISSIONS
+ 493
+ TYPE
+ 1
+ UID
+ 0
+
+
+ CHILDREN
+
+ GID
+ 0
+ PATH
+ Extensions
+ PATH_TYPE
+ 0
+ PERMISSIONS
+ 493
+ TYPE
+ 1
+ UID
+ 0
+
+
+ CHILDREN
+
+ GID
+ 0
+ PATH
+ Filesystems
+ PATH_TYPE
+ 0
+ PERMISSIONS
+ 493
+ TYPE
+ 1
+ UID
+ 0
+
+
+ CHILDREN
+
+ GID
+ 0
+ PATH
+ Frameworks
+ PATH_TYPE
+ 0
+ PERMISSIONS
+ 493
+ TYPE
+ 1
+ UID
+ 0
+
+
+ CHILDREN
+
+ GID
+ 0
+ PATH
+ Input Methods
+ PATH_TYPE
+ 0
+ PERMISSIONS
+ 493
+ TYPE
+ 1
+ UID
+ 0
+
+
+ CHILDREN
+
+ GID
+ 0
+ PATH
+ Internet Plug-Ins
+ PATH_TYPE
+ 0
+ PERMISSIONS
+ 493
+ TYPE
+ 1
+ UID
+ 0
+
+
+ CHILDREN
+
+ GID
+ 0
+ PATH
+ LaunchAgents
+ PATH_TYPE
+ 0
+ PERMISSIONS
+ 493
+ TYPE
+ 1
+ UID
+ 0
+
+
+ CHILDREN
+
+ GID
+ 0
+ PATH
+ LaunchDaemons
+ PATH_TYPE
+ 0
+ PERMISSIONS
+ 493
+ TYPE
+ 1
+ UID
+ 0
+
+
+ CHILDREN
+
+ GID
+ 0
+ PATH
+ PreferencePanes
+ PATH_TYPE
+ 0
+ PERMISSIONS
+ 493
+ TYPE
+ 1
+ UID
+ 0
+
+
+ CHILDREN
+
+ GID
+ 0
+ PATH
+ Preferences
+ PATH_TYPE
+ 0
+ PERMISSIONS
+ 493
+ TYPE
+ 1
+ UID
+ 0
+
+
+ CHILDREN
+
+ GID
+ 80
+ PATH
+ Printers
+ PATH_TYPE
+ 0
+ PERMISSIONS
+ 493
+ TYPE
+ 1
+ UID
+ 0
+
+
+ CHILDREN
+
+ GID
+ 0
+ PATH
+ PrivilegedHelperTools
+ PATH_TYPE
+ 0
+ PERMISSIONS
+ 1005
+ TYPE
+ 1
+ UID
+ 0
+
+
+ CHILDREN
+
+ GID
+ 0
+ PATH
+ QuickLook
+ PATH_TYPE
+ 0
+ PERMISSIONS
+ 493
+ TYPE
+ 1
+ UID
+ 0
+
+
+ CHILDREN
+
+ GID
+ 0
+ PATH
+ QuickTime
+ PATH_TYPE
+ 0
+ PERMISSIONS
+ 493
+ TYPE
+ 1
+ UID
+ 0
+
+
+ CHILDREN
+
+ GID
+ 0
+ PATH
+ Screen Savers
+ PATH_TYPE
+ 0
+ PERMISSIONS
+ 493
+ TYPE
+ 1
+ UID
+ 0
+
+
+ CHILDREN
+
+ GID
+ 0
+ PATH
+ Scripts
+ PATH_TYPE
+ 0
+ PERMISSIONS
+ 493
+ TYPE
+ 1
+ UID
+ 0
+
+
+ CHILDREN
+
+ GID
+ 0
+ PATH
+ Services
+ PATH_TYPE
+ 0
+ PERMISSIONS
+ 493
+ TYPE
+ 1
+ UID
+ 0
+
+
+ CHILDREN
+
+ GID
+ 0
+ PATH
+ Widgets
+ PATH_TYPE
+ 0
+ PERMISSIONS
+ 493
+ TYPE
+ 1
+ UID
+ 0
+
+
+ GID
+ 0
+ PATH
+ Library
+ PATH_TYPE
+ 0
+ PERMISSIONS
+ 493
+ TYPE
+ 1
+ UID
+ 0
+
+
+ CHILDREN
+
+
+ CHILDREN
+
+ GID
+ 0
+ PATH
+ Shared
+ PATH_TYPE
+ 0
+ PERMISSIONS
+ 1023
+ TYPE
+ 1
+ UID
+ 0
+
+
+ GID
+ 80
+ PATH
+ Users
+ PATH_TYPE
+ 0
+ PERMISSIONS
+ 493
+ TYPE
+ 1
+ UID
+ 0
+
+
+ CHILDREN
+
+ GID
+ 80
+ PATH
+ Applications
+ PATH_TYPE
+ 0
+ PERMISSIONS
+ 509
+ TYPE
+ 1
+ UID
+ 0
+
+
+ GID
+ 0
+ PATH
+ /
+ PATH_TYPE
+ 0
+ PERMISSIONS
+ 493
+ TYPE
+ 1
+ UID
+ 0
+
+ PAYLOAD_TYPE
+ 0
+ PRESERVE_EXTENDED_ATTRIBUTES
+
+ SHOW_INVISIBLE
+
+ SPLIT_FORKS
+
+ TREAT_MISSING_FILES_AS_WARNING
+
+ VERSION
+ 5
+
+ PACKAGE_SCRIPTS
+
+ POSTINSTALL_PATH
+
+ PATH_TYPE
+ 0
+
+ PREINSTALL_PATH
+
+ PATH_TYPE
+ 0
+
+ RESOURCES
+
+
+ PACKAGE_SETTINGS
+
+ AUTHENTICATION
+ 1
+ CONCLUSION_ACTION
+ 0
+ FOLLOW_SYMBOLIC_LINKS
+
+ IDENTIFIER
+ com.warmuptill.SceneSwitcher
+ LOCATION
+ 0
+ NAME
+
+ OVERWRITE_PERMISSIONS
+
+ PAYLOAD_SIZE
+ -1
+ REFERENCE_PATH
+
+ RELOCATABLE
+
+ USE_HFS+_COMPRESSION
+
+ VERSION
+ 0.0.2
+
+ PROJECT_COMMENTS
+
+ NOTES
+
+ PCFET0NUWVBFIGh0bWwgUFVCTElDICItLy9XM0MvL0RURCBIVE1M
+ IDQuMDEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvVFIvaHRtbDQv
+ c3RyaWN0LmR0ZCI+CjxodG1sPgo8aGVhZD4KPG1ldGEgaHR0cC1l
+ cXVpdj0iQ29udGVudC1UeXBlIiBjb250ZW50PSJ0ZXh0L2h0bWw7
+ IGNoYXJzZXQ9VVRGLTgiPgo8bWV0YSBodHRwLWVxdWl2PSJDb250
+ ZW50LVN0eWxlLVR5cGUiIGNvbnRlbnQ9InRleHQvY3NzIj4KPHRp
+ dGxlPjwvdGl0bGU+CjxtZXRhIG5hbWU9IkdlbmVyYXRvciIgY29u
+ dGVudD0iQ29jb2EgSFRNTCBXcml0ZXIiPgo8bWV0YSBuYW1lPSJD
+ b2NvYVZlcnNpb24iIGNvbnRlbnQ9IjE0MDQuMTMiPgo8c3R5bGUg
+ dHlwZT0idGV4dC9jc3MiPgo8L3N0eWxlPgo8L2hlYWQ+Cjxib2R5
+ Pgo8L2JvZHk+CjwvaHRtbD4K
+
+
+ PROJECT_SETTINGS
+
+ BUILD_PATH
+
+ PATH
+ ../..
+ PATH_TYPE
+ 1
+
+ EXCLUDED_FILES
+
+
+ PATTERNS_ARRAY
+
+
+ REGULAR_EXPRESSION
+
+ STRING
+ .DS_Store
+ TYPE
+ 0
+
+
+ PROTECTED
+
+ PROXY_NAME
+ Remove .DS_Store files
+ PROXY_TOOLTIP
+ Remove ".DS_Store" files created by the Finder.
+ STATE
+
+
+
+ PATTERNS_ARRAY
+
+
+ REGULAR_EXPRESSION
+
+ STRING
+ .pbdevelopment
+ TYPE
+ 0
+
+
+ PROTECTED
+
+ PROXY_NAME
+ Remove .pbdevelopment files
+ PROXY_TOOLTIP
+ Remove ".pbdevelopment" files created by ProjectBuilder or Xcode.
+ STATE
+
+
+
+ PATTERNS_ARRAY
+
+
+ REGULAR_EXPRESSION
+
+ STRING
+ CVS
+ TYPE
+ 1
+
+
+ REGULAR_EXPRESSION
+
+ STRING
+ .cvsignore
+ TYPE
+ 0
+
+
+ REGULAR_EXPRESSION
+
+ STRING
+ .cvspass
+ TYPE
+ 0
+
+
+ REGULAR_EXPRESSION
+
+ STRING
+ .svn
+ TYPE
+ 1
+
+
+ REGULAR_EXPRESSION
+
+ STRING
+ .git
+ TYPE
+ 1
+
+
+ REGULAR_EXPRESSION
+
+ STRING
+ .gitignore
+ TYPE
+ 0
+
+
+ PROTECTED
+
+ PROXY_NAME
+ Remove SCM metadata
+ PROXY_TOOLTIP
+ Remove helper files and folders used by the CVS, SVN or Git Source Code Management systems.
+ STATE
+
+
+
+ PATTERNS_ARRAY
+
+
+ REGULAR_EXPRESSION
+
+ STRING
+ classes.nib
+ TYPE
+ 0
+
+
+ REGULAR_EXPRESSION
+
+ STRING
+ designable.db
+ TYPE
+ 0
+
+
+ REGULAR_EXPRESSION
+
+ STRING
+ info.nib
+ TYPE
+ 0
+
+
+ PROTECTED
+
+ PROXY_NAME
+ Optimize nib files
+ PROXY_TOOLTIP
+ Remove "classes.nib", "info.nib" and "designable.nib" files within .nib bundles.
+ STATE
+
+
+
+ PATTERNS_ARRAY
+
+
+ REGULAR_EXPRESSION
+
+ STRING
+ Resources Disabled
+ TYPE
+ 1
+
+
+ PROTECTED
+
+ PROXY_NAME
+ Remove Resources Disabled folders
+ PROXY_TOOLTIP
+ Remove "Resources Disabled" folders.
+ STATE
+
+
+
+ SEPARATOR
+
+
+
+ NAME
+ SceneSwitcher
+ PAYLOAD_ONLY
+
+
+
+ TYPE
+ 1
+ VERSION
+ 2
+
+
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a7639a6b..7c624b58 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,9 +8,6 @@ if(BUILD_OUT_OF_TREE)
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)
@@ -56,6 +53,7 @@ if(BUILD_OUT_OF_TREE)
src/general.cpp
src/pause-switch.cpp
src/random.cpp
+ src/time-switch.cpp
)
set(advanced-scene-switcher_UI
@@ -82,6 +80,10 @@ if(BUILD_OUT_OF_TREE)
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}
@@ -181,7 +183,9 @@ else ()
src/general.cpp
src/pause-switch.cpp
src/random.cpp
+ src/time-switch.cpp
)
+
set(advanced-scene-switcher_UI
${advanced-scene-switcher_UI}
forms/advanced-scene-switcher.ui
@@ -190,13 +194,11 @@ else ()
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()
@@ -217,6 +219,7 @@ else ()
${advanced-scene-switcher_PLATFORM_SOURCES}
${advanced-scene-switcher_PLATFORM_HEADERS}
)
+
target_link_libraries(advanced-scene-switcher
${advanced-scene-switcher_PLATFORM_LIBS}
obs-frontend-api
@@ -224,4 +227,4 @@ else ()
libobs)
install_obs_plugin(advanced-scene-switcher data)
-endif()
\ No newline at end of file
+endif()
diff --git a/forms/advanced-scene-switcher.ui b/forms/advanced-scene-switcher.ui
index 9a4f5f64..9de1230b 100644
--- a/forms/advanced-scene-switcher.ui
+++ b/forms/advanced-scene-switcher.ui
@@ -6,8 +6,8 @@
0
0
- 1010
- 560
+ 492
+ 981
@@ -353,6 +353,53 @@
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
-
+
+
+ Use thread priority (experimental)
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 100
+ 0
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
-
@@ -2616,6 +2663,140 @@
+
+
+ Time
+
+
+ -
+
+
-
+
+
+ At
+
+
+
+ -
+
+
+ HH:mm:ss
+
+
+
+ -
+
+
+ switch to
+
+
+
+ -
+
+
+
+ 100
+ 0
+
+
+
+
+ -
+
+
+ using the
+
+
+
+ -
+
+
+ -
+
+
+ transition
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
+ true
+
+
+ true
+
+
+
+ -
+
+
+ 4
+
+
-
+
+
+
+ 22
+ 22
+
+
+
+ true
+
+
+ addIconSmall
+
+
+
+ -
+
+
+
+ 22
+ 22
+
+
+
+ true
+
+
+ removeIconSmall
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
diff --git a/src/advanced-scene-switcher.cpp b/src/advanced-scene-switcher.cpp
index 88275192..0f2196f2 100644
--- a/src/advanced-scene-switcher.cpp
+++ b/src/advanced-scene-switcher.cpp
@@ -57,6 +57,7 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
ui->randomScenes->addItem(name);
ui->fileScenes->addItem(name);
ui->mediaScenes->addItem(name);
+ ui->timeScenes->addItem(name);
temp++;
}
@@ -91,6 +92,7 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
ui->sceneRoundTripScenes2->addItem(PREVIOUS_SCENE_NAME);
ui->idleScenes->addItem(PREVIOUS_SCENE_NAME);
ui->mediaScenes->addItem(PREVIOUS_SCENE_NAME);
+ ui->timeScenes->addItem(PREVIOUS_SCENE_NAME);
obs_frontend_source_list *transitions = new obs_frontend_source_list();
obs_frontend_get_transitions(transitions);
@@ -108,6 +110,7 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
ui->randomTransitions->addItem(name);
ui->fileTransitions->addItem(name);
ui->mediaTransitions->addItem(name);
+ ui->timeTransitions->addItem(name);
}
obs_frontend_source_list_free(transitions);
@@ -305,6 +308,19 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
item->setData(Qt::UserRole, listText);
}
+ for (auto &s : switcher->timeSwitches) {
+ string sceneName = (s.usePreviousScene)
+ ? PREVIOUS_SCENE_NAME
+ : GetWeakSourceName(s.scene);
+ string transitionName = GetWeakSourceName(s.transition);
+ QString listText = MakeTimeSwitchName(
+ sceneName.c_str(), transitionName.c_str(), s.time);
+
+ QListWidgetItem *item =
+ new QListWidgetItem(listText, ui->timeSwitches);
+ item->setData(Qt::UserRole, listText);
+ }
+
ui->idleCheckBox->setChecked(switcher->idleData.idleEnable);
ui->idleScenes->setCurrentText(
switcher->idleData.usePreviousScene
@@ -375,12 +391,19 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
case MEDIA_FUNC:
s = "Media";
break;
+ case TIME_FUNC:
+ s = "Time";
+ break;
}
QString text(s.c_str());
QListWidgetItem *item =
new QListWidgetItem(text, ui->priorityList);
item->setData(Qt::UserRole, text);
}
+
+ for (std::string p : switcher->threadPrioritiesNamesOrderdByPrio) {
+ ui->threadPriority->addItem(p.c_str());
+ }
}
/********************************************************************************
@@ -407,6 +430,7 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
obs_data_array_t *randomArray = obs_data_array_create();
obs_data_array_t *fileArray = obs_data_array_create();
obs_data_array_t *mediaArray = obs_data_array_create();
+ obs_data_array_t *timeArray = obs_data_array_create();
switcher->Prune();
@@ -757,6 +781,35 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
obs_data_release(array_obj);
}
+ for (TimeSwitch &s : switcher->timeSwitches) {
+ obs_data_t *array_obj = obs_data_create();
+
+ obs_source_t *sceneSource =
+ obs_weak_source_get_source(s.scene);
+ obs_source_t *transition =
+ obs_weak_source_get_source(s.transition);
+ if ((s.usePreviousScene || sceneSource) && transition) {
+ const char *sceneName =
+ obs_source_get_name(sceneSource);
+ const char *transitionName =
+ obs_source_get_name(transition);
+ obs_data_set_string(
+ array_obj, "scene",
+ s.usePreviousScene ? PREVIOUS_SCENE_NAME
+ : sceneName);
+ obs_data_set_string(array_obj, "transition",
+ transitionName);
+ obs_data_set_string(
+ array_obj, "time",
+ s.time.toString().toStdString().c_str());
+ obs_data_array_push_back(timeArray, array_obj);
+ }
+ obs_source_release(sceneSource);
+ obs_source_release(transition);
+
+ obs_data_release(array_obj);
+ }
+
string nonMatchingSceneName =
GetWeakSourceName(switcher->nonMatchingScene);
@@ -783,6 +836,7 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
obs_data_set_array(obj, "randomSwitches", randomArray);
obs_data_set_array(obj, "fileSwitches", fileArray);
obs_data_set_array(obj, "mediaSwitches", mediaArray);
+ obs_data_set_array(obj, "timeSwitches", timeArray);
string autoStopSceneName =
GetWeakSourceName(switcher->autoStopScene);
@@ -828,6 +882,8 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
switcher->functionNamesByPriority[5]);
obs_data_set_int(obj, "priority6",
switcher->functionNamesByPriority[6]);
+ obs_data_set_int(obj, "priority7",
+ switcher->functionNamesByPriority[7]);
obs_data_set_obj(save_data, "advanced-scene-switcher", obj);
@@ -844,6 +900,7 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
obs_data_array_release(randomArray);
obs_data_array_release(fileArray);
obs_data_array_release(mediaArray);
+ obs_data_array_release(timeArray);
obs_data_release(obj);
} else {
@@ -876,6 +933,8 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
obs_data_get_array(obj, "fileSwitches");
obs_data_array_t *mediaArray =
obs_data_get_array(obj, "mediaSwitches");
+ obs_data_array_t *timeArray =
+ obs_data_get_array(obj, "timeSwitches");
if (!obj)
obj = obs_data_create();
@@ -1193,6 +1252,36 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
GetWeakTransitionByName(transition), state,
restriction, time,
(strcmp(scene, PREVIOUS_SCENE_NAME) == 0));
+
+ obs_data_release(array_obj);
+ }
+
+ switcher->timeSwitches.clear();
+ count = obs_data_array_count(timeArray);
+
+ for (size_t i = 0; i < count; i++) {
+ obs_data_t *array_obj =
+ obs_data_array_item(timeArray, i);
+
+ const char *scene =
+ obs_data_get_string(array_obj, "scene");
+ const char *transition =
+ obs_data_get_string(array_obj, "transition");
+ QTime time = QTime::fromString(
+ obs_data_get_string(array_obj, "time"));
+
+ string timeSwitchStr =
+ MakeTimeSwitchName(scene, transition, time)
+ .toUtf8()
+ .constData();
+
+ switcher->timeSwitches.emplace_back(
+ GetWeakSourceByName(scene),
+ GetWeakTransitionByName(transition), time,
+ (strcmp(scene, PREVIOUS_SCENE_NAME) == 0),
+ timeSwitchStr);
+
+ obs_data_release(array_obj);
}
string autoStopScene =
@@ -1236,6 +1325,7 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
obs_data_set_default_int(obj, "priority4", DEFAULT_PRIORITY_4);
obs_data_set_default_int(obj, "priority5", DEFAULT_PRIORITY_5);
obs_data_set_default_int(obj, "priority6", DEFAULT_PRIORITY_6);
+ obs_data_set_default_int(obj, "priority7", DEFAULT_PRIORITY_7);
switcher->functionNamesByPriority[0] =
(obs_data_get_int(obj, "priority0"));
@@ -1251,6 +1341,8 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
(obs_data_get_int(obj, "priority5"));
switcher->functionNamesByPriority[6] =
(obs_data_get_int(obj, "priority6"));
+ switcher->functionNamesByPriority[6] =
+ (obs_data_get_int(obj, "priority7"));
if (!switcher->prioFuncsValid()) {
switcher->functionNamesByPriority[0] =
(DEFAULT_PRIORITY_0);
@@ -1266,6 +1358,8 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
(DEFAULT_PRIORITY_5);
switcher->functionNamesByPriority[6] =
(DEFAULT_PRIORITY_6);
+ switcher->functionNamesByPriority[7] =
+ (DEFAULT_PRIORITY_7);
}
obs_data_array_release(array);
@@ -1279,6 +1373,8 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
obs_data_array_release(ignoreIdleWindowsArray);
obs_data_array_release(randomArray);
obs_data_array_release(fileArray);
+ obs_data_array_release(mediaArray);
+ obs_data_array_release(timeArray);
obs_data_release(obj);
@@ -1296,7 +1392,6 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
********************************************************************************/
void SwitcherData::Thread()
{
-
//to avoid scene duplication when rapidly switching scene collection
this_thread::sleep_for(chrono::seconds(2));
@@ -1362,7 +1457,11 @@ void SwitcherData::Thread()
case MEDIA_FUNC:
checkMediaSwitch(match, scene, transition);
break;
+ case TIME_FUNC:
+ checkTimeSwitch(match, scene, transition);
+ break;
}
+
if (switcher->stop) {
goto endLoop;
}
diff --git a/src/headers/advanced-scene-switcher.hpp b/src/headers/advanced-scene-switcher.hpp
index 5bc5cae0..e5be0b4c 100644
--- a/src/headers/advanced-scene-switcher.hpp
+++ b/src/headers/advanced-scene-switcher.hpp
@@ -42,6 +42,7 @@ public:
int executableFindByData(const QString &exe);
int IgnoreIdleWindowsFindByData(const QString &window);
int randomFindByData(const QString &scene);
+ int timeFindByData(const QString &timeStr);
void UpdateNonMatchingScene(const QString &name);
void UpdateAutoStopScene(const QString &name);
@@ -122,6 +123,10 @@ public slots:
void on_mediaAdd_clicked();
void on_mediaRemove_clicked();
+ void on_timeSwitches_currentRowChanged(int idx);
+ void on_timeAdd_clicked();
+ void on_timeRemove_clicked();
+
void on_priorityUp_clicked();
void on_priorityDown_clicked();
diff --git a/src/headers/switcher-data-structs.hpp b/src/headers/switcher-data-structs.hpp
index 371c9d05..b873f7ba 100644
--- a/src/headers/switcher-data-structs.hpp
+++ b/src/headers/switcher-data-structs.hpp
@@ -8,6 +8,7 @@
#include
#include
#include
+#include
#include "utility.hpp"
#define DEFAULT_INTERVAL 300
@@ -23,6 +24,7 @@
#define SCREEN_REGION_FUNC 4
#define WINDOW_TITLE_FUNC 5
#define MEDIA_FUNC 6
+#define TIME_FUNC 7
#define DEFAULT_PRIORITY_0 READ_FILE_FUNC
#define DEFAULT_PRIORITY_1 ROUND_TRIP_FUNC
@@ -31,6 +33,7 @@
#define DEFAULT_PRIORITY_4 SCREEN_REGION_FUNC
#define DEFAULT_PRIORITY_5 WINDOW_TITLE_FUNC
#define DEFAULT_PRIORITY_6 MEDIA_FUNC
+#define DEFAULT_PRIORITY_7 TIME_FUNC
using namespace std;
@@ -227,6 +230,26 @@ struct MediaSwitch {
}
};
+struct TimeSwitch {
+ OBSWeakSource scene;
+ OBSWeakSource transition;
+ QTime time;
+ bool matched;
+ bool usePreviousScene;
+ string timeSwitchStr;
+
+ inline TimeSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
+ QTime time_, bool usePreviousScene_,
+ string timeSwitchStr_)
+ : scene(scene_),
+ transition(transition_),
+ time(time_),
+ usePreviousScene(usePreviousScene_),
+ timeSwitchStr(timeSwitchStr_)
+ {
+ }
+};
+
typedef enum { NO_SWITCH = 0, SWITCH = 1, RANDOM_SWITCH = 2 } NoMatch;
/********************************************************************************
@@ -281,10 +304,24 @@ struct SwitcherData {
vector mediaSwitches;
+ vector timeSwitches;
+
vector functionNamesByPriority = vector{
DEFAULT_PRIORITY_0, DEFAULT_PRIORITY_1, DEFAULT_PRIORITY_2,
DEFAULT_PRIORITY_3, DEFAULT_PRIORITY_4, DEFAULT_PRIORITY_5,
- DEFAULT_PRIORITY_6};
+ DEFAULT_PRIORITY_6, DEFAULT_PRIORITY_7};
+
+ std::vector threadPrioritiesNamesOrderdByPrio{
+ "Lowest", "Low", "Normal", "High", "Highest", "Time critical",
+ };
+ std::map threadPriorities = {
+ {"Lowest", QThread::LowestPriority},
+ {"Low", QThread::LowPriority},
+ {"Normal", QThread::NormalPriority},
+ {"High", QThread::HighPriority},
+ {"Highest", QThread::HighestPriority},
+ {"Time critical", QThread::TimeCriticalPriority},
+ };
void Thread();
void Start();
@@ -315,6 +352,8 @@ struct SwitcherData {
OBSWeakSource &transition, int &delay);
void checkMediaSwitch(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition);
+ void checkTimeSwitch(bool &match, OBSWeakSource &scene,
+ OBSWeakSource &transition);
void Prune()
{
@@ -401,6 +440,13 @@ struct SwitcherData {
fileSwitches.erase(fileSwitches.begin() + i--);
}
+ for (size_t i = 0; i < timeSwitches.size(); i++) {
+ TimeSwitch &s = timeSwitches[i];
+ if (!WeakSourceValid(s.scene) ||
+ !WeakSourceValid(s.transition))
+ timeSwitches.erase(timeSwitches.begin() + i--);
+ }
+
if (!idleData.usePreviousScene &&
!WeakSourceValid(idleData.scene) ||
!WeakSourceValid(idleData.transition)) {
diff --git a/src/headers/utility.hpp b/src/headers/utility.hpp
index c28c92b6..bd8987a0 100644
--- a/src/headers/utility.hpp
+++ b/src/headers/utility.hpp
@@ -5,9 +5,9 @@
#include "switcher-data-structs.hpp"
using namespace std;
-static inline bool WeakSourceValid(obs_weak_source_t* ws)
+static inline bool WeakSourceValid(obs_weak_source_t *ws)
{
- obs_source_t* source = obs_weak_source_get_source(ws);
+ obs_source_t *source = obs_weak_source_get_source(ws);
if (source)
obs_source_release(source);
return !!source;
@@ -119,7 +119,7 @@ static inline QString MakeFileSwitchName(const QString &scene,
return switchName;
}
-typedef enum {
+typedef enum {
TIME_RESTRICTION_NONE,
TIME_RESTRICTION_SHORTER,
TIME_RESTRICTION_LONGER,
@@ -171,6 +171,15 @@ MakeMediaSwitchName(const QString &source, const QString &scene,
return switchName;
}
+static inline QString MakeTimeSwitchName(const QString &scene,
+ const QString &transition, QTime &time)
+{
+ QString switchName = QStringLiteral("At ") + time.toString() +
+ QStringLiteral(" switch to ") + scene +
+ QStringLiteral(" using ") + transition;
+ return switchName;
+}
+
static inline string GetWeakSourceName(obs_weak_source_t *weak_source)
{
string name;
diff --git a/src/priority.cpp b/src/priority.cpp
index caaf99bd..22019b9c 100644
--- a/src/priority.cpp
+++ b/src/priority.cpp
@@ -36,7 +36,7 @@ bool SwitcherData::prioFuncsValid()
for (int p : functionNamesByPriority)
{
- if (p < 0 || p > 6)
+ if (p < 0 || p > 7)
return false;
}
return true;
diff --git a/src/time-switch.cpp b/src/time-switch.cpp
new file mode 100644
index 00000000..e45cd98f
--- /dev/null
+++ b/src/time-switch.cpp
@@ -0,0 +1,147 @@
+#include "headers/advanced-scene-switcher.hpp"
+
+void SceneSwitcher::on_timeSwitches_currentRowChanged(int idx)
+{
+ if (loading)
+ return;
+ if (idx == -1)
+ return;
+
+ QListWidgetItem *item = ui->timeSwitches->item(idx);
+
+ QString timeScenestr = item->data(Qt::UserRole).toString();
+
+ lock_guard lock(switcher->m);
+ for (auto &s : switcher->timeSwitches) {
+ if (timeScenestr.compare(s.timeSwitchStr.c_str()) == 0) {
+ QString sceneName = GetWeakSourceName(s.scene).c_str();
+ QString transitionName =
+ GetWeakSourceName(s.transition).c_str();
+ ui->timeScenes->setCurrentText(sceneName);
+ ui->timeEdit->setTime(s.time);
+ ui->timeTransitions->setCurrentText(transitionName);
+ break;
+ }
+ }
+}
+
+int SceneSwitcher::timeFindByData(const QString &timeStr)
+{
+ QRegExp rx("At " + timeStr + " switch to .*");
+ int count = ui->timeSwitches->count();
+
+ for (int i = 0; i < count; i++) {
+ QListWidgetItem *item = ui->timeSwitches->item(i);
+ QString str = item->data(Qt::UserRole).toString();
+
+ if (rx.exactMatch(str))
+ return i;
+ }
+
+ return -1;
+}
+
+void SceneSwitcher::on_timeAdd_clicked()
+{
+ QString sceneName = ui->timeScenes->currentText();
+ QString transitionName = ui->timeTransitions->currentText();
+ QTime time = ui->timeEdit->time();
+
+ if (sceneName.isEmpty())
+ return;
+
+ OBSWeakSource source = GetWeakSourceByQString(sceneName);
+ OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
+
+ QString text = MakeTimeSwitchName(sceneName, transitionName, time);
+ QVariant v = QVariant::fromValue(text);
+
+ int idx = timeFindByData(time.toString());
+
+ if (idx == -1) {
+ lock_guard lock(switcher->m);
+ switcher->timeSwitches.emplace_back(
+ source, transition, time,
+ (sceneName == QString(PREVIOUS_SCENE_NAME)),
+ text.toUtf8().constData());
+
+ QListWidgetItem *item =
+ new QListWidgetItem(text, ui->timeSwitches);
+ item->setData(Qt::UserRole, v);
+ } else {
+ QListWidgetItem *item = ui->timeSwitches->item(idx);
+ item->setText(text);
+
+ {
+ lock_guard lock(switcher->m);
+ for (auto &s : switcher->timeSwitches) {
+ if (s.time == time) {
+ s.scene = source;
+ s.transition = transition;
+ s.usePreviousScene =
+ (sceneName ==
+ QString(PREVIOUS_SCENE_NAME));
+ s.timeSwitchStr =
+ text.toUtf8().constData();
+ ;
+ break;
+ }
+ }
+ }
+
+ ui->timeSwitches->sortItems();
+ }
+}
+
+void SceneSwitcher::on_timeRemove_clicked()
+{
+ QListWidgetItem *item = ui->timeSwitches->currentItem();
+ if (!item)
+ return;
+
+ string text = item->data(Qt::UserRole).toString().toUtf8().constData();
+
+ {
+ lock_guard lock(switcher->m);
+ auto &switches = switcher->timeSwitches;
+
+ for (auto it = switches.begin(); it != switches.end(); ++it) {
+ auto &s = *it;
+
+ if (s.timeSwitchStr == text) {
+ switches.erase(it);
+ break;
+ }
+ }
+ }
+
+ delete item;
+}
+
+void SwitcherData::checkTimeSwitch(bool &match, OBSWeakSource &scene,
+ OBSWeakSource &transition)
+{
+ if (timeSwitches.size() == 0)
+ return;
+
+ QTime now = QTime::currentTime();
+
+ for (TimeSwitch &s : timeSwitches) {
+
+ QTime validSwitchTimeWindow = s.time.addMSecs(interval);
+
+ match = s.time <= now && now <= validSwitchTimeWindow;
+ if (!match &&
+ validSwitchTimeWindow.msecsSinceStartOfDay() < interval) {
+ // check for overflow
+ match = now >= s.time || now <= validSwitchTimeWindow;
+ }
+
+ if (match) {
+ scene = (s.usePreviousScene) ? previousScene : s.scene;
+ transition = s.transition;
+ match = true;
+ break;
+ }
+ }
+}