Compare commits

..

16 Commits
1.8.1 ... 1.8.2

Author SHA1 Message Date
WarmUpTill
2f0b900745 fix invalid audio matches 2020-12-31 16:59:52 +01:00
WarmUpTill
c6a25f9d85 fix typo 2020-12-31 16:19:58 +01:00
WarmUpTill
e78383d3ed clean up build and build instructions (#92)
* fix build issue with atomic bool initialization

* clean up cmake

* fix warning

* add missing '\' to linux instructions
2020-12-31 15:45:08 +01:00
WarmUpTill
281e9325dd update locale (#91)
* add german locale

* adjust description of ignore window functionality

* adjust order of readWriteSceneFile

* allow translation of 'previous scene'
2020-12-31 14:59:05 +01:00
WarmUpTill
caa2833272 allow pause individual switching methods (#90)
* allow pausing individual switching methods

* clean up pause tab

* allow import of old pauseScenes and pauseWindows
2020-12-31 14:24:09 +01:00
WarmUpTill
fae50024ea rename mediaSources 2020-12-28 17:38:34 +01:00
WarmUpTill
a05e38d3cb fix typos 2020-12-28 17:28:57 +01:00
WarmUpTill
d73749fc3a update README.txt 2020-12-28 17:14:11 +01:00
WarmUpTill
d20cdac5e4 add duration and 'below' condition type options to audio tab (#85) 2020-12-28 17:06:30 +01:00
WarmUpTill
e377be3999 Minor UI changes (#89)
* automatically scroll to new entry

* fix remote file check always matching

* sort combobox entries alphabetically (meida / processes / audio)

* fix some visual issues on non-default OBS themes
2020-12-28 17:03:55 +01:00
WarmUpTill
80e2b3dd14 fix new time matching if QTime is not initialized 2020-12-28 17:02:32 +01:00
WarmUpTill
3a05e61814 add windows installer (#88) 2020-12-23 01:51:48 +01:00
WarmUpTill
dda44a2931 create release artifact (#84) 2020-12-21 22:52:25 +01:00
shugen002
8ba78b12c1 I18n Support (#72)
* adapt UI for i18n

* add placeWidgets() helper function to ease translation

* add hint about Transition Matrix plugin on Transition tab

* translate

* rework UI of file tab

* write status of plugin to scene info file
2020-12-21 11:24:04 +01:00
WarmUpTill
07b95cb8ae do not sleep less than 1ms (#82) 2020-12-13 17:26:59 +01:00
WarmUpTill
faca5f8863 add option to only match if file content changed (#80) 2020-12-12 16:31:07 +01:00
43 changed files with 2576 additions and 1622 deletions

View File

@@ -15,8 +15,8 @@ jobs:
name: "macOS 64-bit" name: "macOS 64-bit"
runs-on: [macos-latest] runs-on: [macos-latest]
env: env:
QT_VERSION: 5.14.1 QT_VERSION: '5.15.2'
MACOS_DEPS_VERSION: '2020-08-30' MACOS_DEPS_VERSION: '2020-12-11'
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2.3.4 uses: actions/checkout@v2.3.4
@@ -180,21 +180,23 @@ jobs:
FILE_DATE=$(date +%Y-%m-%d) FILE_DATE=$(date +%Y-%m-%d)
FILE_NAME=${{ env.PLUGIN_NAME }}-$FILE_DATE-${{ github.sha }}-linux64.tar.gz FILE_NAME=${{ env.PLUGIN_NAME }}-$FILE_DATE-${{ github.sha }}-linux64.tar.gz
echo "FILE_NAME=${FILE_NAME}" >> $GITHUB_ENV echo "FILE_NAME=${FILE_NAME}" >> $GITHUB_ENV
mkdir -p ./${{ env.PLUGIN_NAME }}/bin/64bit/ mkdir -p ./${{ env.LIB_NAME }}/bin/64bit/
mv ./build/UI/frontend-plugins/${{ env.PLUGIN_NAME }}/${{ env.LIB_NAME }}.so ./${{ env.PLUGIN_NAME }}/bin/64bit/${{ env.LIB_NAME }}.so mv ./build/UI/frontend-plugins/${{ env.PLUGIN_NAME }}/${{ env.LIB_NAME }}.so ./${{ env.LIB_NAME }}/bin/64bit/${{ env.LIB_NAME }}.so
tar -cvzf "${FILE_NAME}" ${{ env.PLUGIN_NAME }} mv ./UI/frontend-plugins/${{ env.PLUGIN_NAME }}/data ./${{ env.LIB_NAME }}/data
tar -cvzf "${FILE_NAME}" ${{ env.LIB_NAME }}
- name: 'Publish' - name: 'Publish'
uses: actions/upload-artifact@v2.2.1 uses: actions/upload-artifact@v2.2.1
with: with:
name: '${{ env.FILE_NAME }}' name: '${{ env.FILE_NAME }}'
path: '*.tar.gz' path: '*.tar.gz'
win64: windows:
name: Windows 64-bit name: Windows
runs-on: [windows-latest] runs-on: [windows-latest]
env: env:
QT_VERSION: 5.10.1 QT_VERSION: 5.10.1
CMAKE_GENERATOR: "Visual Studio 16 2019" CMAKE_GENERATOR: "Visual Studio 16 2019"
CMAKE_SYSTEM_VERSION: "10.0.18363.657" CMAKE_SYSTEM_VERSION: "10.0.18363.657"
WINDOWS_DEPS_VERSION: '2017'
steps: steps:
- name: Add msbuild to PATH - name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v1.0.2 uses: microsoft/setup-msbuild@v1.0.2
@@ -218,81 +220,82 @@ jobs:
7z x Qt_${{ env.QT_VERSION }}.7z -o"${{ github.workspace }}/cmbuild/QT" 7z x Qt_${{ env.QT_VERSION }}.7z -o"${{ github.workspace }}/cmbuild/QT"
- name: 'Install prerequisite: Pre-built dependencies' - name: 'Install prerequisite: Pre-built dependencies'
run: | run: |
curl -kLO https://cdn-fastly.obsproject.com/downloads/dependencies2017.zip -f --retry 5 -C - curl -kLO https://cdn-fastly.obsproject.com/downloads/dependencies${{ env.WINDOWS_DEPS_VERSION }}.zip -f --retry 5 -C -
7z x dependencies2017.zip -o"${{ github.workspace }}/cmbuild/deps" 7z x dependencies${{ env.WINDOWS_DEPS_VERSION }}.zip -o"${{ github.workspace }}/cmbuild/deps"
- name: Configure - name: Configure
run: | run: |
mkdir ./build mkdir ./package
mkdir ./build64
cd ./build64
cmake -G"${{ env.CMAKE_GENERATOR }}" -A"x64" -DCMAKE_SYSTEM_VERSION="${{ env.CMAKE_SYSTEM_VERSION }}" -DBUILD_BROWSER=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 "FILE_NAME=${env:FILE_NAME}" >> ${env:GITHUB_ENV}
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.2.1
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.2
- name: Checkout obs
uses: actions/checkout@v2.3.4
with:
repository: obsproject/obs-studio
submodules: 'recursive'
- name: Checkout plugin
uses: actions/checkout@v2.3.4
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 mkdir ./build32
cd ./build32 cd ./build32
cmake -G"${{ env.CMAKE_GENERATOR }}" -A"Win32" -DCMAKE_SYSTEM_VERSION="${{ env.CMAKE_SYSTEM_VERSION }}" -DBUILD_BROWSER=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 .. 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 ..
cd ..
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 - name: Build
run: msbuild /m /p:Configuration=RelWithDebInfo .\build32\obs-studio.sln run: |
msbuild /m /p:Configuration=RelWithDebInfo .\build32\obs-studio.sln
msbuild /m /p:Configuration=RelWithDebInfo .\build64\obs-studio.sln
- name: Package - name: Package
if: success() if: success()
run: | run: |
$env:FILE_DATE=(Get-Date -UFormat "%F") $env:FILE_DATE=(Get-Date -UFormat "%F")
$env:FILE_NAME="${{ env.PLUGIN_NAME }}-${env:FILE_DATE}-${{ github.sha }}-win32.zip" $env:FILE_NAME="${{ env.PLUGIN_NAME }}-${env:FILE_DATE}-${{ github.sha }}-windows"
echo "FILE_NAME=${env:FILE_NAME}" >> ${env:GITHUB_ENV} echo "FILE_NAME=${env:FILE_NAME}" >> ${env:GITHUB_ENV}
robocopy .\build32\rundir\RelWithDebInfo\obs-plugins\32bit\ .\build\obs-plugins\32bit ${{ env.LIB_NAME }}.* /E /XF .gitignore robocopy .\build32\rundir\RelWithDebInfo\obs-plugins\32bit\ .\package\obs-plugins\32bit ${{ env.LIB_NAME }}.* /E /XF .gitignore
7z a ${env:FILE_NAME} .\build\* robocopy .\build64\rundir\RelWithDebInfo\obs-plugins\64bit\ .\package\obs-plugins\64bit ${{ env.LIB_NAME }}.* /E /XF .gitignore
- name: Publish robocopy .\build64\rundir\RelWithDebInfo\data\obs-plugins\${{ env.LIB_NAME }}\ .\package\data\obs-plugins\${{ env.LIB_NAME }}\ /E /XF .gitignore
exit 0
- name: Publish zip
if: success() if: success()
uses: actions/upload-artifact@v2.2.1 uses: actions/upload-artifact@v2.2.1
with: with:
name: '${{ env.FILE_NAME }}' name: '${{ env.FILE_NAME }}'
path: '*-win32.zip' path: package/*
- name: "Package Installer (Prereqs)"
run: |
curl "-kL" "https://github.com/Xaymar/msvc-redist-helper/releases/download/0.1/msvc-redist-helper-64.exe" "-f" "--retry" "5" "-o" "msvc-redist-helper-64.exe"
curl "-kL" "https://github.com/Xaymar/msvc-redist-helper/releases/download/0.1/msvc-redist-helper-32.exe" "-f" "--retry" "5" "-o" "msvc-redist-helper-32.exe"
curl "-kL" "https://files.jrsoftware.org/is/6/innosetup-6.0.3.exe" "-f" "--retry" "5" "-o" "inno.exe"
.\inno.exe /VERYSILENT /SP- /SUPPRESSMSGBOXES /NORESTART
- name: "Package Installer (Compile)"
run: |
& 'C:\Program Files (x86)\Inno Setup 6\ISCC.exe' /Qp ".\build64\UI\frontend-plugins\${{ env.PLUGIN_NAME }}\CI\windows\setup.iss"
- name: Publish installer
if: success()
uses: actions/upload-artifact@v2.2.0
with:
name: '${{ env.FILE_NAME }}-installer'
path: build64/UI/frontend-plugins/SceneSwitcher/CI/windows/Output/*.exe
release:
needs: [macos64, ubuntu64, windows]
name: 'Create Release'
runs-on: [ubuntu-latest]
steps:
- name: "Checkout plugin"
uses: actions/checkout@v2.3.4
with:
path: plugin/${{ env.PLUGIN_NAME }}
- name: Download artifacts
uses: actions/download-artifact@v2
with:
path: artifacts
- name: 'Package'
shell: bash
run: |
mkdir -p ${{ env.PLUGIN_NAME }}/Linux ${{ env.PLUGIN_NAME }}/MacOs ${{ env.PLUGIN_NAME }}/Windows
tar xf artifacts/${{ env.PLUGIN_NAME }}*-linux64.tar.gz/${{ env.PLUGIN_NAME }}*-linux64.tar.gz -C ${{ env.PLUGIN_NAME }}/Linux/
mv artifacts/${{ env.PLUGIN_NAME }}*-macos.pkg/${{ env.PLUGIN_NAME }}*-macos.pkg ${{ env.PLUGIN_NAME }}/MacOs/${{ env.PLUGIN_NAME }}.pkg
mv ./artifacts/${{ env.PLUGIN_NAME }}*-windows/* ${{ env.PLUGIN_NAME }}/Windows/
mv ./artifacts/${{ env.PLUGIN_NAME }}*-windows-installer/*.exe ${{ env.PLUGIN_NAME }}/Windows/
rm ${{ env.PLUGIN_NAME }}/Windows/obs-plugins/32bit/advanced-scene-switcher.pdb
rm ${{ env.PLUGIN_NAME }}/Windows/obs-plugins/64bit/advanced-scene-switcher.pdb
cp plugin/${{ env.PLUGIN_NAME }}/CI/release/README.txt ${{ env.PLUGIN_NAME }}/
FILE_NAME=${{ env.PLUGIN_NAME }}.zip
zip -r ${FILE_NAME} ${{ env.PLUGIN_NAME }}/
- name: Publish
if: success()
uses: actions/upload-artifact@v2.2.1
with:
name: "Release"
path: '*.zip'

View File

@@ -60,6 +60,22 @@
<key>UID</key> <key>UID</key>
<integer>0</integer> <integer>0</integer>
</dict> </dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../data</string>
<key>PATH_TYPE</key>
<integer>1</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
</array> </array>
<key>GID</key> <key>GID</key>
<integer>80</integer> <integer>80</integer>

31
CI/release/README.txt Normal file
View File

@@ -0,0 +1,31 @@
Note that you will have to use OBS version 25 or newer!
--- WINDOWS ---
Recommended: Run the provided installer. (You might have to click 'More info' and select 'Run anyway' if it is blocked by Windows)
Alternatively manually copy the 'obs-plugins' and 'data' folders in the respective OBS Studio installation directory.
It is usually located at 'C:\Program Files (x86)\obs-studio\'.
Remember to install the Visual C++ Redistributable for Visual Studio 2019, if you have not done so already. (See plugin overview page)
--- MAC OS ---
Recommended: Run the provided installer. (You might have to right click and select 'open' if it is blocked)
Alternatively extract the *so file and data folder and either ...
... right click the OBS app inside your Applications folder and choose 'Show Package Contents'.
Copy the advanced-scene-switcher.so file to 'Contents/Plugins' and the 'data' folder to 'Contents/Resources'.
... or copy the advanced-scene-switcher.so file to Library/Application Support/obs-studio/plugins/advanced-scene-switcher/bin/ .
And the 'data' folder to 'Library/Application Support/obs-studio/plugins/advanced-scene-switcher/'.
--- Linux ---
Copy the advanced-scene-switcher.so file and data folder into the OBS Studio plugin folder.
The location of this folder can vary so you might have to look around a bit.
Examples are ...
/usr/lib/obs-plugins/
/usr/lib/x86_64-linux-gnu/obs-plugins/
~/.config/obs-studio/plugins/advanced-scene-switcher/bin/64bit/
The data folder usually should be copied to:
~/.config/obs-studio/plugins/advanced-scene-switcher/

64
CI/windows/setup.iss.in Normal file
View File

@@ -0,0 +1,64 @@
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define MyAppName "Advanced Scene Switcher"
#define MyAppVersion "@GIT_SHA1@"
#define MyAppURL "https://github.com/WarmUpTill/SceneSwitcher"
[Setup]
; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{A4ADDF26-4426-4D2E-B26A-C7C878DA8FC9}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={code:GetDirName}
DefaultGroupName={#MyAppName}
AllowNoIcons=yes
; Uncomment the following line to run in non administrative install mode (install for current user only.)
;PrivilegesRequired=lowest
OutputBaseFilename=AdvancedSceneSwitcherSetup
Compression=lzma
SolidCompression=yes
WizardStyle=modern
ArchitecturesInstallIn64BitMode=x64
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
[Files]
Source: "@ISS_MSVC_REDIST_HELPER_DIR@\msvc-redist-helper-64.exe"; DestDir: "{app}"; DestName: "msvc-redist-helper.exe"; Flags: ignoreversion dontcopy; Check: Is64BitInstallMode
Source: "@ISS_MSVC_REDIST_HELPER_DIR@\msvc-redist-helper-32.exe"; DestDir: "{app}"; DestName: "msvc-redist-helper.exe"; Flags: ignoreversion dontcopy; Check: not Is64BitInstallMode
Source: "@ISS_PLUGIN_FILES_DIR@\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[Icons]
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"
[Code]
// credit where it's due:
// following function comes from https://github.com/Xaymar/obs-studio_amf-encoder-plugin/blob/master/%23Resources/Installer.in.iss#L45
function GetDirName(Value: string): string;
var
InstallPath: string;
begin
// initialize default path, which will be returned when the following registry
// key queries fail due to missing keys or for some different reason
Result := ExpandConstant('{pf}\obs-studio');
// query the first registry value; if this succeeds, return the obtained value
if RegQueryStringValue(HKLM32, 'SOFTWARE\OBS Studio', '', InstallPath) then
Result := InstallPath
end;
procedure CurStepChanged(CurStep: TSetupStep);
var
ResultCode: Integer;
begin
if (CurStep=ssPostInstall) then
begin
ExtractTemporaryFile('msvc-redist-helper.exe');
Exec(ExpandConstant('{tmp}\msvc-redist-helper.exe'), '2019', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
end;
end;

View File

@@ -8,9 +8,15 @@ include(GetGitRevisionDescription)
get_git_head_revision(GIT_REFSPEC GIT_SHA1) get_git_head_revision(GIT_REFSPEC GIT_SHA1)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/version.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/src/version.cpp" @ONLY) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/version.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/src/version.cpp" @ONLY)
if(WIN32)
get_filename_component(ISS_PLUGIN_FILES_DIR "${CMAKE_BINARY_DIR}\\..\\package" ABSOLUTE)
file(TO_NATIVE_PATH "${ISS_PLUGIN_FILES_DIR}" ISS_PLUGIN_FILES_DIR)
get_filename_component(ISS_MSVC_REDIST_HELPER_DIR "${CMAKE_PACKAGE_PREFIX}\\.." ABSOLUTE)
file(TO_NATIVE_PATH "${ISS_MSVC_REDIST_HELPER_DIR}" ISS_MSVC_REDIST_HELPER_DIR)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/CI/windows/setup.iss.in" "${CMAKE_CURRENT_BINARY_DIR}/CI/windows/setup.iss" @ONLY)
endif()
if(BUILD_OUT_OF_TREE) if(BUILD_OUT_OF_TREE)
# out of tree builds
# credits to c3r1c3
set(CMAKE_PREFIX_PATH "${QTDIR}") set(CMAKE_PREFIX_PATH "${QTDIR}")
set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_INCLUDE_CURRENT_DIR ON)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/external") list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/external")
@@ -22,103 +28,107 @@ if(BUILD_OUT_OF_TREE)
find_package(Libcurl REQUIRED) find_package(Libcurl REQUIRED)
find_path(LIBOBS_FRONTEND_INCLUDE_DIR HINTS ${LIBOBS_INCLUDE_DIRS}) find_path(LIBOBS_FRONTEND_INCLUDE_DIR HINTS ${LIBOBS_INCLUDE_DIRS})
find_file(LIBOBS_FRONTEND_API_LIB NAMES libobs-frontend-api.* HINTS ${LIBOBS_LIB} ) find_file(LIBOBS_FRONTEND_API_LIB NAMES libobs-frontend-api.* HINTS ${LIBOBS_LIB} )
endif()
if(APPLE) if(APPLE)
find_library(COCOA Cocoa) find_library(COCOA Cocoa)
if(BUILD_OUT_OF_TREE)
find_package(Qt5MacExtras REQUIRED) find_package(Qt5MacExtras REQUIRED)
include_directories(${COCOA})
add_link_options("-v")
endif() endif()
include_directories(${COCOA})
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 if(UNIX AND NOT APPLE)
${advanced-scene-switcher_HEADERS} find_package(X11 REQUIRED)
src/headers/advanced-scene-switcher.hpp link_libraries(${X11_LIBRARIES})
src/headers/switcher-data-structs.hpp include_directories(${X11_INCLUDE_DIR})
src/headers/utility.hpp endif()
src/headers/curl-helper.hpp
src/headers/switch-audio.hpp
src/headers/switch-executable.hpp
src/headers/switch-file.hpp
src/headers/switch-idle.hpp
src/headers/switch-media.hpp
src/headers/switch-random.hpp
src/headers/switch-screen-region.hpp
src/headers/switch-time.hpp
src/headers/switch-transitions.hpp
src/headers/switch-window.hpp
src/headers/switch-sequence.hpp
src/headers/switch-generic.hpp
src/headers/version.h
)
set(advanced-scene-switcher_SOURCES set(advanced-scene-switcher_HEADERS
${advanced-scene-switcher_SOURCES} ${advanced-scene-switcher_HEADERS}
src/advanced-scene-switcher.cpp src/headers/advanced-scene-switcher.hpp
src/advanced-scene-switcher-module.c src/headers/switcher-data-structs.hpp
src/switcher-data-structs.cpp src/headers/utility.hpp
src/switch-transitions.cpp src/headers/curl-helper.hpp
src/switch-screen-region.cpp src/headers/volume-control.hpp
src/switch-priority.cpp src/headers/switch-audio.hpp
src/switch-executable.cpp src/headers/switch-executable.hpp
src/switch-idle.cpp src/headers/switch-file.hpp
src/switch-sequence.cpp src/headers/switch-idle.hpp
src/switch-file.cpp src/headers/switch-media.hpp
src/switch-window.cpp src/headers/switch-pause.hpp
src/switch-media.cpp src/headers/switch-random.hpp
src/hotkey.cpp src/headers/switch-screen-region.hpp
src/general.cpp src/headers/switch-time.hpp
src/switch-pause.cpp src/headers/switch-transitions.hpp
src/switch-random.cpp src/headers/switch-window.hpp
src/switch-time.cpp src/headers/switch-sequence.hpp
src/switch-audio.cpp src/headers/switch-generic.hpp
src/switch-generic.cpp src/headers/version.h
src/curl-helper.cpp )
src/volume-control.cpp
src/version.cpp
)
set(advanced-scene-switcher_UI set(advanced-scene-switcher_SOURCES
${advanced-scene-switcher_UI} ${advanced-scene-switcher_SOURCES}
forms/advanced-scene-switcher.ui src/advanced-scene-switcher.cpp
) src/advanced-scene-switcher-module.c
src/switcher-data-structs.cpp
src/switch-transitions.cpp
src/switch-screen-region.cpp
src/switch-priority.cpp
src/switch-executable.cpp
src/switch-idle.cpp
src/switch-sequence.cpp
src/switch-file.cpp
src/switch-window.cpp
src/switch-media.cpp
src/hotkey.cpp
src/general.cpp
src/switch-pause.cpp
src/switch-random.cpp
src/switch-time.cpp
src/switch-audio.cpp
src/switch-generic.cpp
src/curl-helper.cpp
src/volume-control.cpp
src/version.cpp
)
if(WIN32) set(advanced-scene-switcher_UI
set(advanced-scene-switcher_PLATFORM_SOURCES ${advanced-scene-switcher_UI}
src/win/advanced-scene-switcher-win.cpp) forms/advanced-scene-switcher.ui
)
elseif(APPLE) if(WIN32)
set(advanced-scene-switcher_PLATFORM_SOURCES set(advanced-scene-switcher_PLATFORM_SOURCES
src/osx/advanced-scene-switcher-osx.mm) src/win/advanced-scene-switcher-win.cpp)
set_source_files_properties(advanced-scene-switcher-osx.mm elseif(APPLE)
PROPERTIES COMPILE_FLAGS "-fobjc-arc") set(advanced-scene-switcher_PLATFORM_SOURCES
set(advanced-scene-switcher_PLATFORM_LIBS src/osx/advanced-scene-switcher-osx.mm)
${COCOA}) 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()
elseif("${CMAKE_SYSTEM_NAME}" MATCHES "Linux") qt5_wrap_ui(advanced-scene-switcher_UI_HEADERS
set(advanced-scene-switcher_PLATFORM_SOURCES ${advanced-scene-switcher_UI}
src/linux/advanced-scene-switcher-nix.cpp) ${advanced-scene-switcher_PLATFORM_UI})
set(advanced-scene-switcher_PLATFORM_LIBS
Xss)
endif()
qt5_wrap_ui(advanced-scene-switcher_UI_HEADERS add_library(advanced-scene-switcher MODULE
${advanced-scene-switcher_UI} ${advanced-scene-switcher_HEADERS}
${advanced-scene-switcher_PLATFORM_UI}) ${advanced-scene-switcher_SOURCES}
${advanced-scene-switcher_UI_HEADERS}
add_library(advanced-scene-switcher MODULE ${advanced-scene-switcher_PLATFORM_SOURCES}
${advanced-scene-switcher_HEADERS} ${advanced-scene-switcher_PLATFORM_HEADERS}
${advanced-scene-switcher_SOURCES} )
${advanced-scene-switcher_UI_HEADERS}
${advanced-scene-switcher_PLATFORM_SOURCES}
${advanced-scene-switcher_PLATFORM_HEADERS}
)
if(BUILD_OUT_OF_TREE)
include_directories( include_directories(
"${LIBOBS_INCLUDE_DIRS}" "${LIBOBS_INCLUDE_DIRS}"
"${LIBOBS_FRONTEND_INCLUDE_DIR}" "${LIBOBS_FRONTEND_INCLUDE_DIR}"
@@ -154,7 +164,6 @@ if(BUILD_OUT_OF_TREE)
# OSX # OSX
if(APPLE) if(APPLE)
set_target_properties(advanced-scene-switcher PROPERTIES PREFIX "") set_target_properties(advanced-scene-switcher PROPERTIES PREFIX "")
endif() endif()
# Linux # Linux
@@ -174,106 +183,12 @@ if(BUILD_OUT_OF_TREE)
install(FILES ${ASS_TRANSLATION_FILES} install(FILES ${ASS_TRANSLATION_FILES}
DESTINATION "${CMAKE_INSTALL_PREFIX}/share/obs/obs-plugins/advanced-scene-switcher/locale") DESTINATION "${CMAKE_INSTALL_PREFIX}/share/obs/obs-plugins/advanced-scene-switcher/locale")
endif() endif()
else () else()
# in-tree build
if(APPLE)
find_library(COCOA Cocoa)
include_directories(${COCOA})
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
src/headers/curl-helper.hpp
src/headers/volume-control.hpp
src/headers/switch-audio.hpp
src/headers/switch-executable.hpp
src/headers/switch-file.hpp
src/headers/switch-idle.hpp
src/headers/switch-media.hpp
src/headers/switch-random.hpp
src/headers/switch-screen-region.hpp
src/headers/switch-time.hpp
src/headers/switch-transitions.hpp
src/headers/switch-window.hpp
src/headers/switch-sequence.hpp
src/headers/switch-generic.hpp
src/headers/version.h
)
set(advanced-scene-switcher_SOURCES
${advanced-scene-switcher_SOURCES}
src/advanced-scene-switcher.cpp
src/advanced-scene-switcher-module.c
src/switcher-data-structs.cpp
src/switch-transitions.cpp
src/switch-screen-region.cpp
src/switch-priority.cpp
src/switch-executable.cpp
src/switch-idle.cpp
src/switch-sequence.cpp
src/switch-file.cpp
src/switch-window.cpp
src/switch-media.cpp
src/hotkey.cpp
src/general.cpp
src/switch-pause.cpp
src/switch-random.cpp
src/switch-time.cpp
src/switch-audio.cpp
src/switch-generic.cpp
src/curl-helper.cpp
src/volume-control.cpp
src/version.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 target_link_libraries(advanced-scene-switcher
${advanced-scene-switcher_PLATFORM_LIBS} ${advanced-scene-switcher_PLATFORM_LIBS}
obs-frontend-api obs-frontend-api
Qt5::Widgets Qt5::Widgets
libobs) libobs)
install_obs_plugin(advanced-scene-switcher data) install_obs_plugin_with_data(advanced-scene-switcher data)
endif() endif()

View File

@@ -49,9 +49,10 @@ Most versions of Linux you can use cmake-gui or the command line.
**For 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>" 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_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)>" -DLIBOBS_LIB="<path to the libobs.so file>" \
-DLIBOBS_FRONTEND_API_LIB="<path to the libobs-frontend-api.so file (usually in the same place as LIBOBS_LIB)>" \
-DCMAKE_INSTALL_PREFIX=/usr .. -DCMAKE_INSTALL_PREFIX=/usr ..
make -j4 make -j4
sudo make install sudo make install

212
data/locale/de-DE.ini Normal file
View File

@@ -0,0 +1,212 @@
AdvSceneSwitcher.pluginName="Erweiterter Automatischer Szenenwechsler"
AdvSceneSwitcher.windowTitle="Erweiterter Automatischer Szenenwechsler"
; General Tab
AdvSceneSwitcher.generalTab.title="Allgemein"
AdvSceneSwitcher.generalTab.status="Status"
AdvSceneSwitcher.generalTab.status.hotkeytips="Hotkeys können in den OBS Einstellungen konfiguriert werden"
AdvSceneSwitcher.generalTab.status.currentStatus="Erweiterter Automatischer Szenenwechsler ist:"
AdvSceneSwitcher.generalTab.status.onStartup="Beim Start:"
AdvSceneSwitcher.generalTab.status.onStartup.asLastRun="Aktiviere den Szenenwechsler wenn er aktiv war"
AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="Aktiviere den Szenenwechsler"
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Aktiviere den Szenenwechsler nicht"
AdvSceneSwitcher.generalTab.status.start="Start"
AdvSceneSwitcher.generalTab.status.stop="Stop"
AdvSceneSwitcher.generalTab.status.checkInterval="Teste Bedingungen alle"
AdvSceneSwitcher.generalTab.generalBehavior="Allgemeines Verhalten"
AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart.recording="Aufnehmen"
AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart.streaming="Streamen"
AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart.recordingAndStreaming="Aufnehmen und Streamen"
AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart1="Starte"
AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart2=" auf Szene"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet="Wenn keine Bedingung erfüllt ist für "
AdvSceneSwitcher.generalTab.generalBehavior.onNoMetDelayTooltip="Kann nur so genau sein wie das eingestellte Interval zum Testen der Bedingungen."
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.dontSwitch="Nicht wechseln"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchToRandom="Wechsle zu einer Szene auf dem Zufall-Tab"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchTo="Wechsle zu:"
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="Ausführliches Logging"
AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStop="Stoppe Streamen/Aufnehmen auf Szene"
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="Deaktiviere UI Tipps"
AdvSceneSwitcher.generalTab.priority="Priorität"
AdvSceneSwitcher.generalTab.priority.description="Szenenwechselmethoden sortiert nach Priorität"
AdvSceneSwitcher.generalTab.priority.threadPriority="Benutze Thread Priorität"
AdvSceneSwitcher.generalTab.priority.threadPriorityNotice="(Erhöhen der Priorität über \"Normal\" ist nicht empfohlen)"
AdvSceneSwitcher.generalTab.saveOrLoadsettings="Speichern / Laden der Einstellungen"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="Exportieren"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="Importieren"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Exportiere Erweiterter Automatischer Szenenwechsler Einstellungen zu Datei ..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Exportiere Erweiterter Automatischer Szenenwechsler Einstellungen von Datei ..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Text Dateien (*.txt)"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="Importieren der Einstellungen ist fehlgeschlagen"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Einstellungen wurden erfolgreich importiert"
AdvSceneSwitcher.generalTab.priority.fileContent="Datei Inhalt"
AdvSceneSwitcher.generalTab.priority.sceneSequence="Szenenfolge"
AdvSceneSwitcher.generalTab.priority.idleDetection="Inaktivitätserkennung"
AdvSceneSwitcher.generalTab.priority.executable="Prozess"
AdvSceneSwitcher.generalTab.priority.screenRegion="Bildschrimbereich"
AdvSceneSwitcher.generalTab.priority.windowTitle="Fenstername"
AdvSceneSwitcher.generalTab.priority.media="Medien"
AdvSceneSwitcher.generalTab.priority.time="Zeit"
AdvSceneSwitcher.generalTab.priority.audio="Audio"
; Transition Tab
AdvSceneSwitcher.transitionTab.title="Szenenübergänge"
AdvSceneSwitcher.transitionTab.transitionOverride="Szenenübergänge, die im Szenenwechsler konfiguriert werden, haben Vorrang vor Übergangsüberschreibung"
AdvSceneSwitcher.transitionTab.transitionForAToB="Szenenübergänge für automatisierte Szenenwechsel von Szene A zu Szene B"
AdvSceneSwitcher.transitionTab.transitionForAToB.description="<html><head/><body><p>Diese Einstellungen beeinflussen <span style=\"font-style:italic;\">nur</span> vom Szenenwechsler ausgelöste Szenenübergänge - Siehe <a href=\"https://obsproject.com/forum/resources/obs-transition-matrix.751/\"><span style=\" text-decoration: underline; color:#268bd2;\">Transition Matrix</span></a> um alle zu konfigurieren.<br/>Einstellungen auf diesem Tab haben Vorrang vor denen welche auf den übrigen Tabs konfiguriert wurden.</p></body></html>"
AdvSceneSwitcher.transitionTab.defaultTransition="Ändere den Szenenübergang wenn eine Szene aktiv ist"
AdvSceneSwitcher.transitionTab.entry="Wechsle von {{scenes}} zu {{scenes2}} mit {{transitions}}"
AdvSceneSwitcher.transitionTab.defaultTransitionEntry="Wenn {{scenes}} aktiv ist ändere den Szenenübergang zu {{transitions}}"
; Pause Scenes Tab
AdvSceneSwitcher.pauseTab.title="Pause"
AdvSceneSwitcher.pauseTab.pauseOnScene="Pausiere den Szenenwechsler auf einer Szene"
AdvSceneSwitcher.pauseTab.pauseInFocus1="Pausiere den Szenenwechsler wenn "
AdvSceneSwitcher.pauseTab.pauseInFocus2="im Fokus ist"
AdvSceneSwitcher.pauseTab.pauseTypeScene="Szene aktiv ist"
AdvSceneSwitcher.pauseTab.pauseTypeWindow="Fenster im Fokus ist"
AdvSceneSwitcher.pauseTab.pauseTargetAll="alle"
AdvSceneSwitcher.pauseTab.pauseEntry="Pausiere {{pauseTargets}} Überprüfungen wenn {{scenes}} {{windows}} {{pauseTypes}}"
; Window Title Tab
AdvSceneSwitcher.windowTitleTab.title="Fenstername"
AdvSceneSwitcher.windowTitleTab.regexrDescription="<html><head/><body><p>Gib entweder den gesamten Fensternamen ein oder eine gültigen regulären Ausdruck. Die Syntax für regulärer Ausdrücke (regex) kann hier überprüft werden: <a href=\"https://regexr.com\"><span style=\" text-decoration: underline; color:#268bd2;\">RegExr</span></a></p></body></html>"
AdvSceneSwitcher.windowTitleTab.stayInFocus1="Ignoriere diesen Fensternamen"
AdvSceneSwitcher.windowTitleTab.stayInFocus2=" "
AdvSceneSwitcher.windowTitleTab.fullscreen="wenn Vollbild"
AdvSceneSwitcher.windowTitleTab.maximized="wenn maximiert"
AdvSceneSwitcher.windowTitleTab.focused="wenn fokussiert"
AdvSceneSwitcher.windowTitleTab.entry="{{windows}} {{scenes}} {{transitions}} {{fullscreen}} {{maximized}} {{focused}}"
; Executable Tab
AdvSceneSwitcher.executableTab.title="Prozess"
AdvSceneSwitcher.executableTab.implemented="Implementiert von dasOven"
AdvSceneSwitcher.executableTab.requiresFocus="nur wenn dieser fokussiert ist"
AdvSceneSwitcher.executableTab.entry="Wenn {{processes}} läuft wechsle zu {{scenes}} mit {{transitions}} {{requiresFocus}}"
; Screen Region Tab
AdvSceneSwitcher.screenRegionTab.title="Bildschrimbereich"
AdvSceneSwitcher.screenRegionTab.currentPosition="Mauszeiger ist bei:"
AdvSceneSwitcher.screenRegionTab.showGuideFrames="Hilfsrahmen einblenden"
AdvSceneSwitcher.screenRegionTab.hideGuideFrames="Hilfsrahmen ausblenden"
AdvSceneSwitcher.screenRegionTab.entry="Wenn der Mauszeiger in {{minX}} {{minY}} x {{maxX}} {{maxY}} ist wechsle zu {{scenes}} mit {{transitions}}"
; Media Tab
AdvSceneSwitcher.mediaTab.title="Medien"
AdvSceneSwitcher.mediaTab.implemented="Implementiert von Exeldro"
AdvSceneSwitcher.mediaTab.states.none="Keine Auswahl"
AdvSceneSwitcher.mediaTab.states.playing="Abspielen"
AdvSceneSwitcher.mediaTab.states.opening="Öffnen"
AdvSceneSwitcher.mediaTab.states.buffering="Buffern"
AdvSceneSwitcher.mediaTab.states.Paused="Pausiert"
AdvSceneSwitcher.mediaTab.states.stopped="Gestoppt"
AdvSceneSwitcher.mediaTab.states.ended="Beendet"
AdvSceneSwitcher.mediaTab.states.error="Fehler"
AdvSceneSwitcher.mediaTab.states.playedToEnd="Zu Ende gespielt"
AdvSceneSwitcher.mediaTab.states.any="Beliebig"
AdvSceneSwitcher.mediaTab.timeRestriction.none="Keine Auswahl"
AdvSceneSwitcher.mediaTab.timeRestriction.shorter="Dauer kürzer"
AdvSceneSwitcher.mediaTab.timeRestriction.longer="Dauer länger"
AdvSceneSwitcher.mediaTab.timeRestriction.remainShorter="übrige Zeit kürzer"
AdvSceneSwitcher.mediaTab.timeRestriction.remainLonger="übrige Zeit länger"
AdvSceneSwitcher.mediaTab.entry="Wenn {{mediaSources}} im Status {{states}} ist und{{timeRestrictions}} {{time}} ist wechsle zu {{scenes}} mit {{transitions}}"
; File Tab
AdvSceneSwitcher.fileTab.title="Datei Inhalt"
AdvSceneSwitcher.fileTab.readWriteSceneFile="Lese / schreibe Szene von / zu Datei"
AdvSceneSwitcher.fileTab.currentSceneOutputFile="Schreibe den Namen der aktiven Szene in folgende Datei:"
AdvSceneSwitcher.fileTab.switchSceneBaseOnFile="Aktiviere Lesen der Szene aus Datei"
AdvSceneSwitcher.fileTab.switchSceneNameInputFile="Lies den Namen der Scene zu der gewechselt werden soll von folgender Datei:"
AdvSceneSwitcher.fileTab.switchSceneBaseOnFileContent="Wechsle Scene basierend auf Datei Inhalt"
AdvSceneSwitcher.fileTab.remoteFileWarning="Vorsicht: Der Szenenwechsler wird versuchen den angegebenen Pfad alle x ms zu öffnen!"
AdvSceneSwitcher.fileTab.remoteFileWarning1="Vorsicht: Der Szenenwechsler öffnet den angegebenen Pfad alle "
AdvSceneSwitcher.fileTab.remoteFileWarning2="ms"
AdvSceneSwitcher.fileTab.libcurlWarning="Laden von libcurl fehlgeschlagen! Erreichen von remote Dateien wird nicht möglich sein!"
AdvSceneSwitcher.fileTab.selectWrite=Datei auswählen in die geschrieben werden soll ..."
AdvSceneSwitcher.fileTab.selectRead="Datei auswählen die gelesen werden soll ..."
AdvSceneSwitcher.fileTab.textFileType="Text Dateien (*.txt)"
AdvSceneSwitcher.fileTab.anyFileType="Beliebige Dateien (*.*)"
AdvSceneSwitcher.fileTab.remote="remote Datei"
AdvSceneSwitcher.fileTab.local="lokale Datei"
AdvSceneSwitcher.fileTab.useRegExp="verwende reguläre Ausdrücke"
AdvSceneSwitcher.fileTab.checkfileContentTime="nur wenn sich das Änderungsdatum geändert"
AdvSceneSwitcher.fileTab.checkfileContent="nur wenn sich der Inhalt geänder hat"
AdvSceneSwitcher.fileTab.entry="Wechsle zu {{scenes}} mit {{transitions}} wenn der Inhalt von {{fileType}} {{filePath}} {{browseButton}} passt zu:"
AdvSceneSwitcher.fileTab.entry2="{{matchText}}"
AdvSceneSwitcher.fileTab.entry3="{{useRegex}} {{checkModificationDate}} {{checkFileContent}}"
; Random Tab
AdvSceneSwitcher.randomTab.title="Zufall"
AdvSceneSwitcher.randomTab.randomDisabledWarning="Funktionalität deaktiviert - Um diese zu aktivieren wähle \"Wenn keine Bedingung erfüllt ist wechsle zu einer Szene auf dem Zufall-Tab\" auf dem Allgemein-Tab aus"
AdvSceneSwitcher.randomTab.entry="Wenn keine Bedingung erfüllt ist wechsle zu {{scenes}} mit {{transitions}} für {{delay}}"
; Time Tab
AdvSceneSwitcher.timeTab.title="Zeit"
AdvSceneSwitcher.timeTab.anyDay="An allen Tagen"
AdvSceneSwitcher.timeTab.mondays="Montags"
AdvSceneSwitcher.timeTab.tuesdays="Dienstags"
AdvSceneSwitcher.timeTab.wednesdays="Mittwochs"
AdvSceneSwitcher.timeTab.thursdays="Donnerstags"
AdvSceneSwitcher.timeTab.fridays="Freitags"
AdvSceneSwitcher.timeTab.saturdays="Samstags"
AdvSceneSwitcher.timeTab.sundays="Sonntags"
AdvSceneSwitcher.timeTab.afterstart="Nach Streamen-/Aufnehmenstart"
AdvSceneSwitcher.timeTab.afterstart.tip="Hier wird die Zeit relativ zum Starten des Streamen/Aufnehmen gemessen"
AdvSceneSwitcher.timeTab.entry="{{triggers}} um {{time}} wechsle zu {{scenes}} mit {{transitions}}"
; Idle Tab
AdvSceneSwitcher.idleTab.title="Inaktivitätserkennung"
AdvSceneSwitcher.idleTab.enable="Aktiviere Inaktivitätserkennung"
AdvSceneSwitcher.idleTab.condition1="Nach "
AdvSceneSwitcher.idleTab.condition2="ohne Keyboard- oder Mauseingaben"
AdvSceneSwitcher.idleTab.switchToScene="wechsle zu Szene"
AdvSceneSwitcher.idleTab.usingTransition1="mit"
AdvSceneSwitcher.idleTab.usingTransition2=" "
AdvSceneSwitcher.idleTab.dontSwitchIfFocus1="Wechsle nicht wenn"
AdvSceneSwitcher.idleTab.dontSwitchIfFocus2="im Fokus ist"
; Scene Sequence Tab
AdvSceneSwitcher.sceneSequenceTab.title="Szenenfolge"
AdvSceneSwitcher.sceneSequenceTab.description="Eine Szenenfolge kann durch Pausieren, Stoppen des Szenenwechslers oder manuelle Szenenwechsel abgebrochen werden"
AdvSceneSwitcher.sceneSequenceTab.save="Speichere Szenenfolgen in eine Datei"
AdvSceneSwitcher.sceneSequenceTab.load="Lade Szenenfolgen von einer Datei"
AdvSceneSwitcher.sceneSequenceTab.saveTitle="Speichere Szenenfolgen in eine Datei ..."
AdvSceneSwitcher.sceneSequenceTab.loadTitle="Wähle eine Datei aus von der Szenenfolgen gelesen werden sollen ..."
AdvSceneSwitcher.sceneSequenceTab.loadFail="Laden der Einstellungen ist fehlgeschlagen!"
AdvSceneSwitcher.sceneSequenceTab.loadSuccess="Laden der Einstellungen war erfolgreich!"
AdvSceneSwitcher.sceneSequenceTab.fileType="Text Dateien (*.txt)"
AdvSceneSwitcher.sceneSequenceTab.entry="Wenn {{startScenes}} aktiv ist wechsle zu {{scenes}} nach {{delay}} {{delayUnits}} mit {{transitions}}"
; Audio Tab
AdvSceneSwitcher.audioTab.title="Audio"
AdvSceneSwitcher.audioTab.condition.above="über"
AdvSceneSwitcher.audioTab.condition.below="unter"
AdvSceneSwitcher.audioTab.entry="Wenn die Lautstärke von {{audioSources}} {{condition}} {{volumeWidget}} ist für {{duration}} wechsle zu {{scenes}} mit {{transitions}}"
; Hotkey
AdvSceneSwitcher.hotkey.startSwitcherHotkey="Starte den Erweiteren Szenenwechsler"
AdvSceneSwitcher.hotkey.stopSwitcherHotkey="Stoppe den Erweiteren Szenenwechsler"
AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="Starte/Stoppe den Erweiteren Szenenwechsler"
AdvSceneSwitcher.close="Schließen"
AdvSceneSwitcher.browse="Öffnen"
AdvSceneSwitcher.selectScene="--Szene auswählen--"
AdvSceneSwitcher.selectPreviousScene="Vorhergehende Szene"
AdvSceneSwitcher.selectTransition="--Szenenübergang auswählen--"
AdvSceneSwitcher.selectWindow="--Fenster auswählen--"
AdvSceneSwitcher.selectAudioSource="--Audio Quelle auswählen--"
AdvSceneSwitcher.selectMediaSource="--Medien Quelle auswählen--"
AdvSceneSwitcher.selectProcess="--Prozess auswählen--"
AdvSceneSwitcher.enterPath="--Pfad eingeben--"
AdvSceneSwitcher.enterText="--Text eingeben--"
AdvSceneSwitcher.invaildEntriesWillNotBeSaved="Ungültige Einträge werden nicht gespeichert"
AdvSceneSwitcher.selectWindowTip="Benutze \"OBS\" um das OBS-Studio Fenster auszuwählen\nBenutze\"Task Switching\"um die ALT + TAB Tastenkombination auszuwählen"
AdvSceneSwitcher.status.active="Aktiv"
AdvSceneSwitcher.status.inactive="Inaktiv"
AdvSceneSwitcher.unit.milliseconds="Millisekunden"
AdvSceneSwitcher.unit.secends="Sekunden"
AdvSceneSwitcher.unit.minutes="Minuten"
AdvSceneSwitcher.unit.hours="Stunden"

212
data/locale/en-US.ini Normal file
View File

@@ -0,0 +1,212 @@
AdvSceneSwitcher.pluginName="Advanced Scene Switcher"
AdvSceneSwitcher.windowTitle="Advanced Scene Switcher"
; General Tab
AdvSceneSwitcher.generalTab.title="General"
AdvSceneSwitcher.generalTab.status="Status"
AdvSceneSwitcher.generalTab.status.hotkeytips="Hotkeys can be defined in the OBS settings"
AdvSceneSwitcher.generalTab.status.currentStatus="Advanced Scene Switcher is:"
AdvSceneSwitcher.generalTab.status.onStartup="On startup:"
AdvSceneSwitcher.generalTab.status.onStartup.asLastRun="Start the scene switcher if it was running"
AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="Always start the scene switcher"
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Do not start the scene switcher"
AdvSceneSwitcher.generalTab.status.start="Start"
AdvSceneSwitcher.generalTab.status.stop="Stop"
AdvSceneSwitcher.generalTab.status.checkInterval="Check switch conditions every"
AdvSceneSwitcher.generalTab.generalBehavior="General behavior"
AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart.recording="Recording"
AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart.streaming="Streaming"
AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart.recordingAndStreaming="Recording and Streaming"
AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart1="Automatically start"
AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart2="on scene"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet="If no switch condition is met for"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMetDelayTooltip="Will only ever be as accurate as the configured check interval."
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.dontSwitch="Don't switch"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchToRandom="Switch to any scene in Random tab"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchTo="Switch to:"
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="Enable verbose logging"
AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStop="Automatically stop streaming/recording on scene"
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="Disable UI hints"
AdvSceneSwitcher.generalTab.priority="Priority"
AdvSceneSwitcher.generalTab.priority.description="Switching methods priority (Highest priority is at the top)"
AdvSceneSwitcher.generalTab.priority.threadPriority="Use thread priority"
AdvSceneSwitcher.generalTab.priority.threadPriorityNotice="(Raising the priority above \"Normal\" is not recommended)"
AdvSceneSwitcher.generalTab.saveOrLoadsettings="Save / load settings"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="Export"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="Import"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Export Advanced Scene Switcher settings to file ..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Import Advanced Scene Switcher settings from file ..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Text files (*.txt)"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="Advanced Scene Switcher failed to import settings"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Advanced Scene Switcher settings imported successfully"
AdvSceneSwitcher.generalTab.priority.fileContent="File Content"
AdvSceneSwitcher.generalTab.priority.sceneSequence="Scene Sequence"
AdvSceneSwitcher.generalTab.priority.idleDetection="Idle Detection"
AdvSceneSwitcher.generalTab.priority.executable="Executable"
AdvSceneSwitcher.generalTab.priority.screenRegion="Screen Region"
AdvSceneSwitcher.generalTab.priority.windowTitle="Window Title"
AdvSceneSwitcher.generalTab.priority.media="Media"
AdvSceneSwitcher.generalTab.priority.time="Time"
AdvSceneSwitcher.generalTab.priority.audio="Audio"
; Transition Tab
AdvSceneSwitcher.transitionTab.title="Transition"
AdvSceneSwitcher.transitionTab.transitionOverride="Scene transitions defined in the scene switcher take priority over Transition Overrides defined per scene"
AdvSceneSwitcher.transitionTab.transitionForAToB="Use transition for automated scene switch from scene A to scene B"
AdvSceneSwitcher.transitionTab.transitionForAToB.description="<html><head/><body><p>These settings <span style=\"font-style:italic;\">only</span> affect transitions caused by the scene switcher - Check out <a href=\"https://obsproject.com/forum/resources/obs-transition-matrix.751/\"><span style=\" text-decoration: underline; color:#268bd2;\">Transition Matrix</span></a> if you want to configure this for manual scene changes.<br/>Settings defined here take priority over transition settings configured elsewhere in the scene switcher.</p></body></html>"
AdvSceneSwitcher.transitionTab.defaultTransition="Change transition if scene is active"
AdvSceneSwitcher.transitionTab.entry="Switch from {{scenes}} to {{scenes2}} using {{transitions}}"
AdvSceneSwitcher.transitionTab.defaultTransitionEntry="When scene {{scenes}} is active change default scene transition to {{transitions}}"
; Pause Scenes Tab
AdvSceneSwitcher.pauseTab.title="Pause"
AdvSceneSwitcher.pauseTab.pauseOnScene="Pause the Scene Switcher on scene"
AdvSceneSwitcher.pauseTab.pauseInFocus1="Pause the Scene Switcher when "
AdvSceneSwitcher.pauseTab.pauseInFocus2="is in focus"
AdvSceneSwitcher.pauseTab.pauseTypeScene="scene is active"
AdvSceneSwitcher.pauseTab.pauseTypeWindow="window is in focus"
AdvSceneSwitcher.pauseTab.pauseTargetAll="all"
AdvSceneSwitcher.pauseTab.pauseEntry="Pause {{pauseTargets}} checks when {{pauseTypes}} {{scenes}} {{windows}}"
; Window Title Tab
AdvSceneSwitcher.windowTitleTab.title="Title"
AdvSceneSwitcher.windowTitleTab.regexrDescription="<html><head/><body><p>Enter either direct window titles or valid regex. You can check syntax and matches for regular expressions using <a href=\"https://regexr.com\"><span style=\" text-decoration: underline; color:#268bd2;\">RegExr</span></a></p></body></html>"
AdvSceneSwitcher.windowTitleTab.stayInFocus1="Ignore this window name"
AdvSceneSwitcher.windowTitleTab.stayInFocus2=" "
AdvSceneSwitcher.windowTitleTab.fullscreen="if fullscreen"
AdvSceneSwitcher.windowTitleTab.maximized="if maximized"
AdvSceneSwitcher.windowTitleTab.focused="if focused"
AdvSceneSwitcher.windowTitleTab.entry="{{windows}} {{scenes}} {{transitions}} {{fullscreen}} {{maximized}} {{focused}}"
; Executable Tab
AdvSceneSwitcher.executableTab.title="Executable"
AdvSceneSwitcher.executableTab.implemented="Implemented by dasOven"
AdvSceneSwitcher.executableTab.requiresFocus="only if focused"
AdvSceneSwitcher.executableTab.entry="When {{processes}} is running switch to {{scenes}} using {{transitions}} {{requiresFocus}}"
; Screen Region Tab
AdvSceneSwitcher.screenRegionTab.title="Region"
AdvSceneSwitcher.screenRegionTab.currentPosition="Cursor is currently at:"
AdvSceneSwitcher.screenRegionTab.showGuideFrames="Show guide frames"
AdvSceneSwitcher.screenRegionTab.hideGuideFrames="Hide guide frames"
AdvSceneSwitcher.screenRegionTab.entry="If cursor is in {{minX}} {{minY}} x {{maxX}} {{maxY}} switch to {{scenes}} using {{transitions}}"
; Media Tab
AdvSceneSwitcher.mediaTab.title="Media"
AdvSceneSwitcher.mediaTab.implemented="Implemented by Exeldro"
AdvSceneSwitcher.mediaTab.states.none="None"
AdvSceneSwitcher.mediaTab.states.playing="Playing"
AdvSceneSwitcher.mediaTab.states.opening="Opening"
AdvSceneSwitcher.mediaTab.states.buffering="Buffering"
AdvSceneSwitcher.mediaTab.states.Paused="Paused"
AdvSceneSwitcher.mediaTab.states.stopped="Stopped"
AdvSceneSwitcher.mediaTab.states.ended="Ended"
AdvSceneSwitcher.mediaTab.states.error="Error"
AdvSceneSwitcher.mediaTab.states.playedToEnd="Played to end"
AdvSceneSwitcher.mediaTab.states.any="Any"
AdvSceneSwitcher.mediaTab.timeRestriction.none="None"
AdvSceneSwitcher.mediaTab.timeRestriction.shorter="Time shorter"
AdvSceneSwitcher.mediaTab.timeRestriction.longer="Time longer"
AdvSceneSwitcher.mediaTab.timeRestriction.remainShorter="Time remaining shorter"
AdvSceneSwitcher.mediaTab.timeRestriction.remainLonger="Time remaining longer"
AdvSceneSwitcher.mediaTab.entry="When {{mediaSources}} state is {{states}} and {{timeRestrictions}} {{time}} switch to {{scenes}} using {{transitions}}"
; File Tab
AdvSceneSwitcher.fileTab.title="File"
AdvSceneSwitcher.fileTab.readWriteSceneFile="Read / write scene from / to file"
AdvSceneSwitcher.fileTab.currentSceneOutputFile="Write the name of the current scene to this file:"
AdvSceneSwitcher.fileTab.switchSceneBaseOnFile="Enable switching of scenes based on file input"
AdvSceneSwitcher.fileTab.switchSceneNameInputFile="Read scene name to be switched to from this file:"
AdvSceneSwitcher.fileTab.switchSceneBaseOnFileContent="Switch scene based on file contents"
AdvSceneSwitcher.fileTab.remoteFileWarning="Please note that if you choose the remote option the scene switcher will try to access the remote location every x ms as specified on the General tab!"
AdvSceneSwitcher.fileTab.remoteFileWarning1="Note that the scene switcher will try to access the remote location every "
AdvSceneSwitcher.fileTab.remoteFileWarning2="ms"
AdvSceneSwitcher.fileTab.libcurlWarning="Failed to load libcurl! Accessing remote files will not be possible!"
AdvSceneSwitcher.fileTab.selectWrite="Select a file to write to ..."
AdvSceneSwitcher.fileTab.selectRead="Select a file to read from ..."
AdvSceneSwitcher.fileTab.textFileType="Text files (*.txt)"
AdvSceneSwitcher.fileTab.anyFileType="Any files (*.*)"
AdvSceneSwitcher.fileTab.remote="remote file"
AdvSceneSwitcher.fileTab.local="local file"
AdvSceneSwitcher.fileTab.useRegExp="use regular expressions (pattern matching)"
AdvSceneSwitcher.fileTab.checkfileContentTime="if modification date changed"
AdvSceneSwitcher.fileTab.checkfileContent="if content changed"
AdvSceneSwitcher.fileTab.entry="Switch to {{scenes}} using {{transitions}} if content of {{fileType}} {{filePath}} {{browseButton}} matches:"
AdvSceneSwitcher.fileTab.entry2="{{matchText}}"
AdvSceneSwitcher.fileTab.entry3="{{useRegex}} {{checkModificationDate}} {{checkFileContent}}"
; Random Tab
AdvSceneSwitcher.randomTab.title="Random"
AdvSceneSwitcher.randomTab.randomDisabledWarning="Functionality disabled - To activate select \"If no switch condition is met switch to any scene in Random tab\" on General tab"
AdvSceneSwitcher.randomTab.entry="If no switch condition is met switch to {{scenes}} using {{transitions}} for {{delay}}"
; Time Tab
AdvSceneSwitcher.timeTab.title="Time"
AdvSceneSwitcher.timeTab.anyDay="On any day"
AdvSceneSwitcher.timeTab.mondays="Mondays"
AdvSceneSwitcher.timeTab.tuesdays="Tuesdays"
AdvSceneSwitcher.timeTab.wednesdays="Wednesdays"
AdvSceneSwitcher.timeTab.thursdays="Thursdays"
AdvSceneSwitcher.timeTab.fridays="Fridays"
AdvSceneSwitcher.timeTab.saturdays="Saturdays"
AdvSceneSwitcher.timeTab.sundays="Sundays"
AdvSceneSwitcher.timeTab.afterstart="After streaming/recording start"
AdvSceneSwitcher.timeTab.afterstart.tip="The time relative to the start of streaming / recording will be used"
AdvSceneSwitcher.timeTab.entry="{{triggers}} at {{time}} switch to {{scenes}} using {{transitions}}"
; Idle Tab
AdvSceneSwitcher.idleTab.title="Idle"
AdvSceneSwitcher.idleTab.enable="Enable Idle Detection"
AdvSceneSwitcher.idleTab.condition1="After "
AdvSceneSwitcher.idleTab.condition2="of no keyboard or mouse inputs "
AdvSceneSwitcher.idleTab.switchToScene="switch to scene"
AdvSceneSwitcher.idleTab.usingTransition1="using the"
AdvSceneSwitcher.idleTab.usingTransition2="transition"
AdvSceneSwitcher.idleTab.dontSwitchIfFocus1="Do not switch if"
AdvSceneSwitcher.idleTab.dontSwitchIfFocus2="is in focus"
; Scene Sequence Tab
AdvSceneSwitcher.sceneSequenceTab.title="Sequence"
AdvSceneSwitcher.sceneSequenceTab.description="A sequence of automatic scene switches can be cancelled by either pausing/stopping the scene switcher or manually switching to a different scene"
AdvSceneSwitcher.sceneSequenceTab.save="Save scene sequences to file"
AdvSceneSwitcher.sceneSequenceTab.load="Load scene sequences from file"
AdvSceneSwitcher.sceneSequenceTab.saveTitle="Save Scene Sequence to file ..."
AdvSceneSwitcher.sceneSequenceTab.loadTitle="Select a file to read Scene Sequence from ..."
AdvSceneSwitcher.sceneSequenceTab.loadFail="Advanced Scene Switcher failed to import settings!"
AdvSceneSwitcher.sceneSequenceTab.loadSuccess="Advanced Scene Switcher settings imported successfully!"
AdvSceneSwitcher.sceneSequenceTab.fileType="Text files (*.txt)"
AdvSceneSwitcher.sceneSequenceTab.entry="When {{startScenes}} is active switch to {{scenes}} after {{delay}} {{delayUnits}} using {{transitions}}"
; Audio Tab
AdvSceneSwitcher.audioTab.title="Audio"
AdvSceneSwitcher.audioTab.condition.above="above"
AdvSceneSwitcher.audioTab.condition.below="below"
AdvSceneSwitcher.audioTab.entry="When the volume of {{audioSources}} is {{condition}} {{volumeWidget}} for {{duration}} switch to {{scenes}} using {{transitions}}"
; Hotkey
AdvSceneSwitcher.hotkey.startSwitcherHotkey="Start the Advanced Scene Switcher"
AdvSceneSwitcher.hotkey.stopSwitcherHotkey="Stop the Advanced Scene Switcher"
AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="Toggle Start/Stop for the Advanced Scene Switcher"
AdvSceneSwitcher.close="Close"
AdvSceneSwitcher.browse="Browse"
AdvSceneSwitcher.selectScene="--select scene--"
AdvSceneSwitcher.selectPreviousScene="Previous Scene"
AdvSceneSwitcher.selectTransition="--select transition--"
AdvSceneSwitcher.selectWindow="--select window--"
AdvSceneSwitcher.selectAudioSource="--select audio source--"
AdvSceneSwitcher.selectMediaSource="--select media source--"
AdvSceneSwitcher.selectProcess="--select process--"
AdvSceneSwitcher.enterPath="--enter path--"
AdvSceneSwitcher.enterText="--enter text--"
AdvSceneSwitcher.invaildEntriesWillNotBeSaved="invalid entries will not be saved"
AdvSceneSwitcher.selectWindowTip="Use \"OBS\" to specify OBS window\nUse \"Task Switching\"to specify ALT + TAB"
AdvSceneSwitcher.status.active="Active"
AdvSceneSwitcher.status.inactive="Inactive"
AdvSceneSwitcher.unit.milliseconds="milliseconds"
AdvSceneSwitcher.unit.secends="seconds"
AdvSceneSwitcher.unit.minutes="minutes"
AdvSceneSwitcher.unit.hours="hours"

206
data/locale/zh-CN.ini Normal file
View File

@@ -0,0 +1,206 @@
AdvSceneSwitcher.pluginName="高级场景切换器"
AdvSceneSwitcher.windowTitle="高级场景切换器"
; General Tab
AdvSceneSwitcher.generalTab.title="通用"
AdvSceneSwitcher.generalTab.status="状态"
AdvSceneSwitcher.generalTab.status.hotkeytips="快捷键可在OBS设置中设置"
AdvSceneSwitcher.generalTab.status.currentStatus="当前状态:"
AdvSceneSwitcher.generalTab.status.onStartup="在OBS启动时"
AdvSceneSwitcher.generalTab.status.onStartup.asLastRun="按照最后运行时的状态"
AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="总是自动启动"
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="不要启动"
AdvSceneSwitcher.generalTab.status.start="启动"
AdvSceneSwitcher.generalTab.status.stop="停止"
AdvSceneSwitcher.generalTab.status.checkInterval="检查切换条件时间间隔"
AdvSceneSwitcher.generalTab.generalBehavior="一般表现"
AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart.recording="录制"
AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart.streaming="推流"
AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart.recordingAndStreaming="录制和推流"
AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart1="自动开始"
AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart2="当切换到场景时"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet="如果不符合任何切换条件"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMetDelayTooltip="时间精度最高只能达到配置的轮询间隔"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.dontSwitch="不切换"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchToRandom="切换到随机场景列表中任意随机场景"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchTo="切换到"
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="详细日志输出"
AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStop="当切换到场景时自动停止推流和录制"
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="禁用UI提示"
AdvSceneSwitcher.generalTab.priority="优先级"
AdvSceneSwitcher.generalTab.priority.description="切换场景优先级 (最上方的项优先级最高)"
AdvSceneSwitcher.generalTab.priority.threadPriority="使用线程优先级"
AdvSceneSwitcher.generalTab.priority.threadPriorityNotice="(不推荐使用高于 \"Normal\" 的优先级)"
AdvSceneSwitcher.generalTab.saveOrLoadsettings="导出或导入设置"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="导出设置"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="导入设置"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="导出高级场景切换器到文件..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="导入高级场景切换器到文件..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="文本文件 (*.txt)"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="高级场景切换器导入设置失败"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="高级场景切换器导入设置成功"
AdvSceneSwitcher.generalTab.priority.fileContent="文件内容"
AdvSceneSwitcher.generalTab.priority.sceneSequence="场景序列"
AdvSceneSwitcher.generalTab.priority.idleDetection="闲置检测"
AdvSceneSwitcher.generalTab.priority.executable="程序"
AdvSceneSwitcher.generalTab.priority.screenRegion="屏幕区域"
AdvSceneSwitcher.generalTab.priority.windowTitle="窗口标题"
AdvSceneSwitcher.generalTab.priority.media="媒体"
AdvSceneSwitcher.generalTab.priority.time="时间"
AdvSceneSwitcher.generalTab.priority.audio="音频"
; Transition Tab
AdvSceneSwitcher.transitionTab.title="转场特效"
AdvSceneSwitcher.transitionTab.transitionOverride="在场景切换器中设定的转场特效优先级高于场景设定的转场特效"
AdvSceneSwitcher.transitionTab.transitionForAToB="当自动从场景A切换到场景B时使用的转场特效"
AdvSceneSwitcher.transitionTab.transitionForAToB.description="<html><head/><body><p>这里的设定<span style=\"font-style:bold;\">只影响由场景切换器引起的转场有效</span>,不影响你手动的引起的转场。<br/>在这里设定的转场特效优先级高于场景切换器其他地方设置的</p></body></html>"
AdvSceneSwitcher.transitionTab.defaultTransition="当切换到这个场景时修改默认转场特效"
AdvSceneSwitcher.transitionTab.switchDefaultLabel="活跃时切换默认转场特效为"
AdvSceneSwitcher.transitionTab.entry="从场景 {{scenes}} 切换到场景 {{scenes2}} 时使用转场特效 {{transitions}}"
AdvSceneSwitcher.transitionTab.defaultTransitionEntry="当场景 {{scenes}} 被激活时更改默认转场特效为 {{transitions}}"
; Pause Scenes Tab
AdvSceneSwitcher.pauseTab.title="暂停"
AdvSceneSwitcher.pauseTab.pauseOnScene="当切换到这个场景时暂停场景切换器"
AdvSceneSwitcher.pauseTab.pauseInFocus1="当窗口"
AdvSceneSwitcher.pauseTab.pauseInFocus2="获得焦点时暂停场景切换器"
; Window Title Tab
AdvSceneSwitcher.windowTitleTab.title="窗口标题"
AdvSceneSwitcher.windowTitleTab.regexrDescription="<html><head/><body><p>你可以直接输入窗口标题或正则表达式. 你可以使用<a href=\"https://regexr.com\"><span style=\" text-decoration: underline; color:#268bd2;\">RegExr</span></a>来检查验证你的正则表达式</p></body></html>"
AdvSceneSwitcher.windowTitleTab.stayInFocus1="当前焦点窗口标题为"
AdvSceneSwitcher.windowTitleTab.stayInFocus2="时保持当前场景"
AdvSceneSwitcher.windowTitleTab.fullscreen="全屏时"
AdvSceneSwitcher.windowTitleTab.maximized="最大化时"
AdvSceneSwitcher.windowTitleTab.focused="窗口聚集时"
AdvSceneSwitcher.windowTitleTab.entry="{{windows}} {{scenes}} {{transitions}} {{fullscreen}} {{maximized}} {{focused}}"
; Executable Tab
AdvSceneSwitcher.executableTab.title="程序"
AdvSceneSwitcher.executableTab.implemented="感谢dasOven的实现"
AdvSceneSwitcher.executableTab.requiresFocus="仅获得焦点时"
AdvSceneSwitcher.executableTab.entry="当 {{processes}} 正在运行时使用 {{transitions}} 切换到 {{scenes}} {{requiresFocus}}"
; Screen Region Tab
AdvSceneSwitcher.screenRegionTab.title="屏幕区域"
AdvSceneSwitcher.screenRegionTab.currentPosition="鼠标当前位置:"
AdvSceneSwitcher.screenRegionTab.showGuideFrames="显示区域边界"
AdvSceneSwitcher.screenRegionTab.hideGuideFrames="隐藏区域边界"
AdvSceneSwitcher.screenRegionTab.entry="如果鼠标在 {{minX}} {{minY}} x {{maxX}} {{maxY}} 使用转场特效 {{transitions}} 切换到场景 {{scenes}}"
; Media Tab
AdvSceneSwitcher.mediaTab.title="媒体"
AdvSceneSwitcher.mediaTab.implemented="感谢Exeldro的实现"
AdvSceneSwitcher.mediaTab.states.none="空"
AdvSceneSwitcher.mediaTab.states.playing="播放中"
AdvSceneSwitcher.mediaTab.states.opening="正在打开"
AdvSceneSwitcher.mediaTab.states.buffering="缓冲中"
AdvSceneSwitcher.mediaTab.states.Paused="暂停"
AdvSceneSwitcher.mediaTab.states.stopped="停止"
AdvSceneSwitcher.mediaTab.states.ended="结束"
AdvSceneSwitcher.mediaTab.states.error="错误"
AdvSceneSwitcher.mediaTab.states.any="任意"
AdvSceneSwitcher.mediaTab.timeRestriction.none="无"
AdvSceneSwitcher.mediaTab.timeRestriction.shorter="播放时间小于"
AdvSceneSwitcher.mediaTab.timeRestriction.longer="播放时间大于"
AdvSceneSwitcher.mediaTab.timeRestriction.remainShorter="剩余时间少于"
AdvSceneSwitcher.mediaTab.timeRestriction.remainLonger="剩余时间多于"
AdvSceneSwitcher.mediaTab.entry="当 {{mediaSources}} 状态为 {{states}} 并且 {{timeRestrictions}} {{time}} 时使用转场特效 {{transitions}} 切换到场景 {{scenes}}"
; File Tab
AdvSceneSwitcher.fileTab.title="文件"
AdvSceneSwitcher.fileTab.readWriteSceneFile="从文件加载或保存当前场景名"
AdvSceneSwitcher.fileTab.currentSceneOutputFile="将当前场景写入到这个文件:"
AdvSceneSwitcher.fileTab.switchSceneBaseOnFile="启用从文件读取应切换到的场景名"
AdvSceneSwitcher.fileTab.switchSceneNameInputFile="从这个文件读取应切换到的场景名:"
AdvSceneSwitcher.fileTab.switchSceneBaseOnFileContent="根据文件内容切换场景"
AdvSceneSwitcher.fileTab.remoteFileWarning="请注意 如果你使用网络文件,场景切换器会按照你在通用页设置的间隔时间尝试访问网络文件!"
AdvSceneSwitcher.fileTab.remoteFileWarning1="注意,场景切换器会每 "
AdvSceneSwitcher.fileTab.remoteFileWarning2="毫秒尝试访问网络文件"
AdvSceneSwitcher.fileTab.libcurlWarning="无法加载 libcurl 库! 访问网络文件功能将不可用!"
AdvSceneSwitcher.fileTab.selectWrite="写入到文件..."
AdvSceneSwitcher.fileTab.selectRead="从文件读取..."
AdvSceneSwitcher.fileTab.textFileType="文本文件 (*.txt)"
AdvSceneSwitcher.fileTab.anyFileType="任意文件 (*.*)"
AdvSceneSwitcher.fileTab.remote="网络"
AdvSceneSwitcher.fileTab.local="本地"
AdvSceneSwitcher.fileTab.useRegExp="使用正则表达式(模式匹配)"
AdvSceneSwitcher.fileTab.checkfileContentTime="仅当文件修改时间改变时检查文件内容"
AdvSceneSwitcher.fileTab.checkfileContent="仅当文件发生修改时"
AdvSceneSwitcher.fileTab.entry="如果 {{fileType}} 文件 {{filePath}} {{browseButton}} 匹配下列规则,使用转场特效 {{transitions}} 切换到场景 {{scenes}}"
AdvSceneSwitcher.fileTab.entry2="{{matchText}}"
AdvSceneSwitcher.fileTab.entry3="{{useRegex}} {{checkModificationDate}} {{checkFileContent}}"
; Random Tab
AdvSceneSwitcher.randomTab.title="随机场景列表"
AdvSceneSwitcher.randomTab.randomDisabledWarning="功能已被禁用 - 可通过在通用页设置\"如果不符合任何切换条件切换到随机场景列表中任意随机场景\"启用"
AdvSceneSwitcher.randomTab.entry="如果没有切换器条件满足,使用转场特效 {{transitions}} 切换到场景 {{scenes}} 并停留 {{delay}}"
; Time Tab
AdvSceneSwitcher.timeTab.title="时间"
AdvSceneSwitcher.timeTab.anyDay="每天"
AdvSceneSwitcher.timeTab.mondays="每周一"
AdvSceneSwitcher.timeTab.tuesdays="每周二"
AdvSceneSwitcher.timeTab.wednesdays="每周三"
AdvSceneSwitcher.timeTab.thursdays="每周四"
AdvSceneSwitcher.timeTab.fridays="每周五"
AdvSceneSwitcher.timeTab.saturdays="每周六"
AdvSceneSwitcher.timeTab.sundays="每周日"
AdvSceneSwitcher.timeTab.afterstart="推流或录制开始后"
AdvSceneSwitcher.timeTab.afterstart.tip="相对于直播或录制开始之后的时间点"
AdvSceneSwitcher.timeTab.entry="{{triggers}} 的 {{time}} 使用转场特效 {{transitions}} 切换到场景 {{scenes}}"
; Idle Tab
AdvSceneSwitcher.idleTab.title="闲置检测"
AdvSceneSwitcher.idleTab.enable="启用闲置检测"
AdvSceneSwitcher.idleTab.condition1="超过"
AdvSceneSwitcher.idleTab.condition2="没有鼠标或键盘操作"
AdvSceneSwitcher.idleTab.switchToScene="切换到场景"
AdvSceneSwitcher.idleTab.usingTransition1="使用"
AdvSceneSwitcher.idleTab.usingTransition2="转场特效"
AdvSceneSwitcher.idleTab.dontSwitchIfFocus1="如果当前窗口焦点在"
AdvSceneSwitcher.idleTab.dontSwitchIfFocus2="时不切换"
; Scene Sequence Tab
AdvSceneSwitcher.sceneSequenceTab.title="场景序列"
AdvSceneSwitcher.sceneSequenceTab.description="自动场景序列可以通过暂停或停止场景切换器或者手动切换到其他场景来取消"
AdvSceneSwitcher.sceneSequenceTab.save="保存当前序列到文件"
AdvSceneSwitcher.sceneSequenceTab.load="从文件加载序列"
AdvSceneSwitcher.sceneSequenceTab.saveTitle="保存当前序列到文件 ..."
AdvSceneSwitcher.sceneSequenceTab.loadTitle="从文件加载序列 ..."
AdvSceneSwitcher.sceneSequenceTab.loadFail="导入失败"
AdvSceneSwitcher.sceneSequenceTab.loadSuccess="导入失败成功"
AdvSceneSwitcher.sceneSequenceTab.fileType="文本文件 (*.txt)"
AdvSceneSwitcher.sceneSequenceTab.entry="当场景 {{startScenes}} 被激活 {{delay}} {{delayUnits}}后使用转场特效 {{transitions}} 切换到场景 {{scenes}}"
; Audio Tab
AdvSceneSwitcher.audioTab.title="音频"
AdvSceneSwitcher.audioTab.entry="当{{audioSources}} is {{condition}} {{volumeWidget}} for {{duration}} 使用转场特效 {{transitions}} 切换到场景 {{scenes}}"
; Hotkey
AdvSceneSwitcher.hotkey.startSwitcherHotkey="启动高级场景切换器"
AdvSceneSwitcher.hotkey.stopSwitcherHotkey="停止高级场景切换器"
AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="切换(启动/停止)高级场景切换器"
AdvSceneSwitcher.close="关闭"
AdvSceneSwitcher.browse="浏览文件"
AdvSceneSwitcher.selectScene="--选择场景--"
AdvSceneSwitcher.selectTransition="--选择转场特效--"
AdvSceneSwitcher.selectWindow="--选择窗口--"
AdvSceneSwitcher.selectAudioSource="--选择音频源--"
AdvSceneSwitcher.selectMediaSource="--选择媒体源--"
AdvSceneSwitcher.selectProcess="--选择进程--"
AdvSceneSwitcher.enterPath="--输入路径--"
AdvSceneSwitcher.enterText="--输入文本--"
AdvSceneSwitcher.invaildEntriesWillNotBeSaved="无效项将不会被保存"
AdvSceneSwitcher.selectWindowTip="使用 \"OBS\" 来指定OBS窗口\n使用 \"Task Switching\" 来指定 Alt + Tab"
AdvSceneSwitcher.status.active="运行中"
AdvSceneSwitcher.status.inactive="已停止"
AdvSceneSwitcher.unit.milliseconds="毫秒"
AdvSceneSwitcher.unit.secends="秒"
AdvSceneSwitcher.unit.minutes="分钟"
AdvSceneSwitcher.unit.hours="小时"

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,15 @@
#include <obs-module.h> #include <obs-module.h>
#include <obs-frontend-api.h>
OBS_DECLARE_MODULE() OBS_DECLARE_MODULE()
OBS_MODULE_USE_DEFAULT_LOCALE("advanced-scene-switcher", "en-US")
void InitSceneSwitcher(); void InitSceneSwitcher();
void FreeSceneSwitcher(); void FreeSceneSwitcher();
bool obs_module_load(void) bool obs_module_load(void)
{ {
obs_frontend_push_ui_translation(obs_module_get_string);
InitSceneSwitcher(); InitSceneSwitcher();
return true; return true;
} }

View File

@@ -4,6 +4,7 @@
#include <QPropertyAnimation> #include <QPropertyAnimation>
#include <QGraphicsColorizeEffect> #include <QGraphicsColorizeEffect>
#include <obs-module.h>
#include <obs-frontend-api.h> #include <obs-frontend-api.h>
#include <util/util.hpp> #include <util/util.hpp>
@@ -77,8 +78,10 @@ void AdvSceneSwitcher::populateSceneSelection(QComboBox *sel, bool addPrevious,
bool addSelect) bool addSelect)
{ {
if (addSelect) if (addSelect)
addSelectionEntry(sel, "--select scene--", addSelectionEntry(
"invalid entries will not be saved"); sel, obs_module_text("AdvSceneSwitcher.selectScene"),
obs_module_text(
"AdvSceneSwitcher.invaildEntriesWillNotBeSaved"));
BPtr<char *> scenes = obs_frontend_get_scene_names(); BPtr<char *> scenes = obs_frontend_get_scene_names();
char **temp = scenes; char **temp = scenes;
@@ -89,14 +92,17 @@ void AdvSceneSwitcher::populateSceneSelection(QComboBox *sel, bool addPrevious,
} }
if (addPrevious) if (addPrevious)
sel->addItem(previous_scene_name); sel->addItem(obs_module_text(
"AdvSceneSwitcher.selectPreviousScene"));
} }
void AdvSceneSwitcher::populateTransitionSelection(QComboBox *sel, void AdvSceneSwitcher::populateTransitionSelection(QComboBox *sel,
bool addSelect) bool addSelect)
{ {
if (addSelect) if (addSelect)
addSelectionEntry(sel, "--select transition--"); addSelectionEntry(
sel,
obs_module_text("AdvSceneSwitcher.selectTransition"));
obs_frontend_source_list *transitions = new obs_frontend_source_list(); obs_frontend_source_list *transitions = new obs_frontend_source_list();
obs_frontend_get_transitions(transitions); obs_frontend_get_transitions(transitions);
@@ -113,7 +119,8 @@ void AdvSceneSwitcher::populateTransitionSelection(QComboBox *sel,
void AdvSceneSwitcher::populateWindowSelection(QComboBox *sel, bool addSelect) void AdvSceneSwitcher::populateWindowSelection(QComboBox *sel, bool addSelect)
{ {
if (addSelect) if (addSelect)
addSelectionEntry(sel, "--select window--"); addSelectionEntry(
sel, obs_module_text("AdvSceneSwitcher.selectWindow"));
std::vector<std::string> windows; std::vector<std::string> windows;
GetWindowList(windows); GetWindowList(windows);
@@ -124,66 +131,105 @@ void AdvSceneSwitcher::populateWindowSelection(QComboBox *sel, bool addSelect)
} }
#ifdef WIN32 #ifdef WIN32
sel->setItemData( sel->setItemData(0, obs_module_text("AdvSceneSwitcher.selectWindowTip"),
0, Qt::ToolTipRole);
"Use \"OBS\" to specify OBS window\nUse \"Task Switching\"to specify ALT + TAB",
Qt::ToolTipRole);
#endif #endif
} }
void AdvSceneSwitcher::populateAudioSelection(QComboBox *sel, bool addSelect) void AdvSceneSwitcher::populateAudioSelection(QComboBox *sel, bool addSelect)
{ {
if (addSelect) if (addSelect)
addSelectionEntry(sel, "--select audio source--", addSelectionEntry(
"invalid entries will not be saved"); sel,
obs_module_text("AdvSceneSwitcher.selectAudioSource"),
obs_module_text(
"AdvSceneSwitcher.invaildEntriesWillNotBeSaved"));
auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */ auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */
{ {
QComboBox *combo = reinterpret_cast<QComboBox *>(data); std::vector<std::string> *list =
reinterpret_cast<std::vector<std::string> *>(data);
uint32_t flags = obs_source_get_output_flags(source); uint32_t flags = obs_source_get_output_flags(source);
if ((flags & OBS_SOURCE_AUDIO) != 0) { if ((flags & OBS_SOURCE_AUDIO) != 0) {
const char *name = obs_source_get_name(source); list->push_back(obs_source_get_name(source));
combo->addItem(name);
} }
return true; return true;
}; };
obs_enum_sources(sourceEnum, sel); std::vector<std::string> audioSources;
obs_enum_sources(sourceEnum, &audioSources);
sort(audioSources.begin(), audioSources.end());
for (std::string &source : audioSources) {
sel->addItem(source.c_str());
}
} }
void AdvSceneSwitcher::populateMediaSelection(QComboBox *sel, bool addSelect) void AdvSceneSwitcher::populateMediaSelection(QComboBox *sel, bool addSelect)
{ {
if (addSelect) if (addSelect)
addSelectionEntry(sel, "--select media source--", addSelectionEntry(
"invalid entries will not be saved"); sel,
obs_module_text("AdvSceneSwitcher.selectMediaSource"),
obs_module_text(
"AdvSceneSwitcher.invaildEntriesWillNotBeSaved"));
auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */ auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */
{ {
QComboBox *combo = reinterpret_cast<QComboBox *>(data); std::vector<std::string> *list =
reinterpret_cast<std::vector<std::string> *>(data);
std::string sourceId = obs_source_get_id(source); std::string sourceId = obs_source_get_id(source);
if (sourceId.compare("ffmpeg_source") == 0 || if (sourceId.compare("ffmpeg_source") == 0 ||
sourceId.compare("vlc_source") == 0) { sourceId.compare("vlc_source") == 0) {
const char *name = obs_source_get_name(source); list->push_back(obs_source_get_name(source));
combo->addItem(name);
} }
return true; return true;
}; };
obs_enum_sources(sourceEnum, sel); std::vector<std::string> mediaSources;
obs_enum_sources(sourceEnum, &mediaSources);
sort(mediaSources.begin(), mediaSources.end());
for (std::string &source : mediaSources) {
sel->addItem(source.c_str());
}
} }
void AdvSceneSwitcher::populateProcessSelection(QComboBox *sel, bool addSelect) void AdvSceneSwitcher::populateProcessSelection(QComboBox *sel, bool addSelect)
{ {
if (addSelect) if (addSelect)
addSelectionEntry(sel, "--select process--"); addSelectionEntry(
sel, obs_module_text("AdvSceneSwitcher.selectProcess"));
QStringList processes; QStringList processes;
GetProcessList(processes); GetProcessList(processes);
processes.sort();
for (QString &process : processes) for (QString &process : processes)
sel->addItem(process); sel->addItem(process);
} }
void AdvSceneSwitcher::listAddClicked(QListWidget *list,
SwitchWidget *newWidget,
QPushButton *addButton,
QMetaObject::Connection *addHighlight)
{
if (!list || !newWidget) {
blog(LOG_WARNING,
"listAddClicked called without valid list or widget");
return;
}
if (addButton && addHighlight)
addButton->disconnect(*addHighlight);
QListWidgetItem *item;
item = new QListWidgetItem(list);
list->addItem(item);
item->setSizeHint(newWidget->minimumSizeHint());
list->setItemWidget(item, newWidget);
list->scrollToItem(item);
}
bool AdvSceneSwitcher::listMoveUp(QListWidget *list) bool AdvSceneSwitcher::listMoveUp(QListWidget *list)
{ {
int index = list->currentRow(); int index = list->currentRow();
@@ -354,13 +400,16 @@ void SwitcherData::Thread()
} else { } else {
duration = duration =
std::chrono::milliseconds(interval) - runTime; std::chrono::milliseconds(interval) - runTime;
if (duration.count() < 0) if (duration.count() < 1) {
duration = std::chrono::milliseconds(0); blog(LOG_INFO,
"detected busy loop - refusing to sleep less than 1ms");
duration = std::chrono::milliseconds(50);
}
} }
//sleep for a bit //sleep for a bit
if (verbose) if (verbose)
blog(LOG_INFO, "sleep for %d", duration.count()); blog(LOG_INFO, "sleep for %ld", duration.count());
cv.wait_for(lock, duration); cv.wait_for(lock, duration);
startTime = std::chrono::high_resolution_clock::now(); startTime = std::chrono::high_resolution_clock::now();
@@ -483,6 +532,9 @@ void SwitcherData::Start()
switcher->th = new SwitcherThread(); switcher->th = new SwitcherThread();
switcher->th->start( switcher->th->start(
(QThread::Priority)switcher->threadPriority); (QThread::Priority)switcher->threadPriority);
// Will be overwritten quickly but might be useful
writeToStatusFile("Advanced Scene Switcher running");
} }
} }
@@ -495,6 +547,8 @@ void SwitcherData::Stop()
th->wait(); th->wait();
delete th; delete th;
th = nullptr; th = nullptr;
writeToStatusFile("Advanced Scene Switcher stopped");
} }
} }
@@ -591,7 +645,7 @@ extern "C" void InitSceneSwitcher()
blog(LOG_INFO, "version: %s", g_GIT_SHA1); blog(LOG_INFO, "version: %s", g_GIT_SHA1);
QAction *action = (QAction *)obs_frontend_add_tools_menu_qaction( QAction *action = (QAction *)obs_frontend_add_tools_menu_qaction(
"Advanced Scene Switcher"); obs_module_text("AdvSceneSwitcher.pluginName"));
switcher = new SwitcherData; switcher = new SwitcherData;

View File

@@ -94,15 +94,19 @@ void AdvSceneSwitcher::on_checkInterval_valueChanged(int value)
void AdvSceneSwitcher::SetStarted() void AdvSceneSwitcher::SetStarted()
{ {
ui->toggleStartButton->setText("Stop"); ui->toggleStartButton->setText(
ui->pluginRunningText->setText("Active"); obs_module_text("AdvSceneSwitcher.generalTab.status.stop"));
ui->pluginRunningText->setText(
obs_module_text("AdvSceneSwitcher.status.active"));
ui->pluginRunningText->disconnect(inactivePluse); ui->pluginRunningText->disconnect(inactivePluse);
} }
void AdvSceneSwitcher::SetStopped() void AdvSceneSwitcher::SetStopped()
{ {
ui->toggleStartButton->setText("Start"); ui->toggleStartButton->setText(
ui->pluginRunningText->setText("Inactive"); obs_module_text("AdvSceneSwitcher.generalTab.status.start"));
ui->pluginRunningText->setText(
obs_module_text("AdvSceneSwitcher.status.inactive"));
inactivePluse = PulseWidget(ui->pluginRunningText, QColor(Qt::red), inactivePluse = PulseWidget(ui->pluginRunningText, QColor(Qt::red),
QColor(0, 0, 0, 0), "QLabel "); QColor(0, 0, 0, 0), "QLabel ");
} }
@@ -280,8 +284,12 @@ void AdvSceneSwitcher::on_uiHintsDisable_stateChanged(int state)
void AdvSceneSwitcher::on_exportSettings_clicked() void AdvSceneSwitcher::on_exportSettings_clicked()
{ {
QString directory = QFileDialog::getSaveFileName( QString directory = QFileDialog::getSaveFileName(
this, tr("Export Advanced Scene Switcher settings to file ..."), this,
QDir::currentPath(), tr("Text files (*.txt)")); tr(obs_module_text(
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle")),
QDir::currentPath(),
tr(obs_module_text(
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType")));
if (directory.isEmpty()) if (directory.isEmpty())
return; return;
@@ -317,8 +325,11 @@ void AdvSceneSwitcher::on_importSettings_clicked()
QString directory = QFileDialog::getOpenFileName( QString directory = QFileDialog::getOpenFileName(
this, this,
tr("Import Advanced Scene Switcher settings from file ..."), tr(obs_module_text(
QDir::currentPath(), tr("Text files (*.txt)")); "AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle")),
QDir::currentPath(),
tr(obs_module_text(
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType")));
if (directory.isEmpty()) if (directory.isEmpty())
return; return;
@@ -331,8 +342,8 @@ void AdvSceneSwitcher::on_importSettings_clicked()
if (!obj) { if (!obj) {
QMessageBox Msgbox; QMessageBox Msgbox;
Msgbox.setText( Msgbox.setText(obs_module_text(
"Advanced Scene Switcher failed to import settings"); "AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail"));
Msgbox.exec(); Msgbox.exec();
return; return;
} }
@@ -355,8 +366,8 @@ void AdvSceneSwitcher::on_importSettings_clicked()
obs_data_release(obj); obs_data_release(obj);
QMessageBox Msgbox; QMessageBox Msgbox;
Msgbox.setText( Msgbox.setText(obs_module_text(
"Advanced Scene Switcher settings imported successfully"); "AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess"));
Msgbox.exec(); Msgbox.exec();
close(); close();
} }
@@ -374,7 +385,7 @@ int findTabIndex(QTabWidget *tabWidget, int pos)
tabName = "transitionsTab"; tabName = "transitionsTab";
break; break;
case 2: case 2:
tabName = "pauseScenesTab"; tabName = "pauseTab";
break; break;
case 3: case 3:
tabName = "windowTitleTab"; tabName = "windowTitleTab";
@@ -688,8 +699,8 @@ void AdvSceneSwitcher::setupGeneralTab()
ui->noMatchSwitchScene->setCurrentText( ui->noMatchSwitchScene->setCurrentText(
GetWeakSourceName(switcher->nonMatchingScene).c_str()); GetWeakSourceName(switcher->nonMatchingScene).c_str());
ui->noMatchDelay->setValue(switcher->noMatchDelay); ui->noMatchDelay->setValue(switcher->noMatchDelay);
ui->noMatchDelay->setToolTip( ui->noMatchDelay->setToolTip(obs_module_text(
"Will only ever be as accurate as the configured check interval."); "AdvSceneSwitcher.generalTab.generalBehavior.onNoMetDelayTooltip"));
ui->checkInterval->setValue(switcher->interval); ui->checkInterval->setValue(switcher->interval);
ui->autoStopSceneCheckBox->setChecked(switcher->autoStopEnable); ui->autoStopSceneCheckBox->setChecked(switcher->autoStopEnable);
@@ -702,9 +713,12 @@ void AdvSceneSwitcher::setupGeneralTab()
ui->autoStopScenes->setDisabled(true); ui->autoStopScenes->setDisabled(true);
} }
ui->autoStartType->addItem("Recording"); ui->autoStartType->addItem(obs_module_text(
ui->autoStartType->addItem("Streaming"); "AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart.recording"));
ui->autoStartType->addItem("Recording and Streaming"); ui->autoStartType->addItem(obs_module_text(
"AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart.streaming"));
ui->autoStartType->addItem(obs_module_text(
"AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart.recordingAndStreaming"));
ui->autoStartSceneCheckBox->setChecked(switcher->autoStartEnable); ui->autoStartSceneCheckBox->setChecked(switcher->autoStartEnable);
ui->autoStartScenes->setCurrentText( ui->autoStartScenes->setCurrentText(
@@ -726,31 +740,40 @@ void AdvSceneSwitcher::setupGeneralTab()
std::string s = ""; std::string s = "";
switch (p) { switch (p) {
case read_file_func: case read_file_func:
s = "File Content"; s = obs_module_text(
"AdvSceneSwitcher.generalTab.priority.fileContent");
break; break;
case round_trip_func: case round_trip_func:
s = "Scene Sequence"; s = obs_module_text(
"AdvSceneSwitcher.generalTab.priority.sceneSequence");
break; break;
case idle_func: case idle_func:
s = "Idle Detection"; s = obs_module_text(
"AdvSceneSwitcher.generalTab.priority.idleDetection");
break; break;
case exe_func: case exe_func:
s = "Executable"; s = obs_module_text(
"AdvSceneSwitcher.generalTab.priority.executable");
break; break;
case screen_region_func: case screen_region_func:
s = "Screen Region"; s = obs_module_text(
"AdvSceneSwitcher.generalTab.priority.screenRegion");
break; break;
case window_title_func: case window_title_func:
s = "Window Title"; s = obs_module_text(
"AdvSceneSwitcher.generalTab.priority.windowTitle");
break; break;
case media_func: case media_func:
s = "Media"; s = obs_module_text(
"AdvSceneSwitcher.generalTab.priority.media");
break; break;
case time_func: case time_func:
s = "Time"; s = obs_module_text(
"AdvSceneSwitcher.generalTab.priority.time");
break; break;
case audio_func: case audio_func:
s = "Audio"; s = obs_module_text(
"AdvSceneSwitcher.generalTab.priority.audio");
break; break;
} }
QString text(s.c_str()); QString text(s.c_str());
@@ -772,10 +795,12 @@ void AdvSceneSwitcher::setupGeneralTab()
} }
} }
ui->startupBehavior->addItem( ui->startupBehavior->addItem(obs_module_text(
"Start the scene switcher if it was running"); "AdvSceneSwitcher.generalTab.status.onStartup.asLastRun"));
ui->startupBehavior->addItem("Always start the scene switcher"); ui->startupBehavior->addItem(obs_module_text(
ui->startupBehavior->addItem("Do not start the scene switcher"); "AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart"));
ui->startupBehavior->addItem(obs_module_text(
"AdvSceneSwitcher.generalTab.status.onStartup.doNotStart"));
ui->startupBehavior->setCurrentIndex(switcher->startupBehavior); ui->startupBehavior->setCurrentIndex(switcher->startupBehavior);

View File

@@ -31,8 +31,6 @@ public:
void SetHideFrames(); void SetHideFrames();
void clearFrames(QListWidget *list); void clearFrames(QListWidget *list);
int PauseScenesFindByData(const QString &scene);
int PauseWindowsFindByData(const QString &window);
int IgnoreWindowsFindByData(const QString &window); int IgnoreWindowsFindByData(const QString &window);
int IgnoreIdleWindowsFindByData(const QString &window); int IgnoreIdleWindowsFindByData(const QString &window);
@@ -75,6 +73,9 @@ public:
QColor = QColor(0, 0, 0, 0), QColor = QColor(0, 0, 0, 0),
QString specifier = "QLabel "); QString specifier = "QLabel ");
void listAddClicked(QListWidget *list, SwitchWidget *newWidget,
QPushButton *addButton = nullptr,
QMetaObject::Connection *addHighlight = nullptr);
bool listMoveUp(QListWidget *list); bool listMoveUp(QListWidget *list);
bool listMoveDown(QListWidget *list); bool listMoveDown(QListWidget *list);
@@ -101,13 +102,10 @@ public slots:
void on_screenRegionUp_clicked(); void on_screenRegionUp_clicked();
void on_screenRegionDown_clicked(); void on_screenRegionDown_clicked();
void on_pauseScenes_currentRowChanged(int idx); void on_pauseUp_clicked();
void on_pauseScenesAdd_clicked(); void on_pauseDown_clicked();
void on_pauseScenesRemove_clicked(); void on_pauseAdd_clicked();
void on_pauseRemove_clicked();
void on_pauseWindows_currentRowChanged(int idx);
void on_pauseWindowsAdd_clicked();
void on_pauseWindowsRemove_clicked();
void on_ignoreWindows_currentRowChanged(int idx); void on_ignoreWindows_currentRowChanged(int idx);
void on_ignoreWindowsAdd_clicked(); void on_ignoreWindowsAdd_clicked();
@@ -145,7 +143,6 @@ public slots:
void on_browseButton_clicked(); void on_browseButton_clicked();
void on_readFileCheckBox_stateChanged(int state); void on_readFileCheckBox_stateChanged(int state);
void on_fileType_currentIndexChanged(int idx);
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();
@@ -168,8 +165,7 @@ public slots:
void on_fileAdd_clicked(); void on_fileAdd_clicked();
void on_fileRemove_clicked(); void on_fileRemove_clicked();
void on_fileScenesList_currentRowChanged(int idx); void on_fileSwitches_currentRowChanged(int idx);
void on_browseButton_3_clicked();
void on_fileUp_clicked(); void on_fileUp_clicked();
void on_fileDown_clicked(); void on_fileDown_clicked();

View File

@@ -7,9 +7,18 @@
constexpr auto audio_func = 8; constexpr auto audio_func = 8;
constexpr auto default_priority_8 = audio_func; constexpr auto default_priority_8 = audio_func;
typedef enum {
ABOVE,
BELOW,
} audioCondition;
struct AudioSwitch : virtual SceneSwitcherEntry { struct AudioSwitch : virtual SceneSwitcherEntry {
static bool pause;
OBSWeakSource audioSource = nullptr; OBSWeakSource audioSource = nullptr;
int volumeThreshold = 0; int volumeThreshold = 0;
audioCondition condition = ABOVE;
double duration = 0;
unsigned int matchCount = 0;
float peak = -1; float peak = -1;
obs_volmeter_t *volmeter = nullptr; obs_volmeter_t *volmeter = nullptr;
@@ -25,6 +34,7 @@ struct AudioSwitch : virtual SceneSwitcherEntry {
AudioSwitch(){}; AudioSwitch(){};
AudioSwitch(OBSWeakSource scene_, OBSWeakSource transition_, AudioSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
OBSWeakSource audioSource_, int volumeThreshold_, OBSWeakSource audioSource_, int volumeThreshold_,
audioCondition condition_, double duration_,
bool usePreviousScene_); bool usePreviousScene_);
AudioSwitch(const AudioSwitch &other); AudioSwitch(const AudioSwitch &other);
AudioSwitch(AudioSwitch &&other); AudioSwitch(AudioSwitch &&other);
@@ -49,17 +59,15 @@ public:
private slots: private slots:
void SourceChanged(const QString &text); void SourceChanged(const QString &text);
void VolumeThresholdChanged(int vol); void VolumeThresholdChanged(int vol);
void ConditionChanged(int cond);
void DurationChanged(double dur);
private: private:
QComboBox *audioSources; QComboBox *audioSources;
QComboBox *condition;
QSpinBox *audioVolumeThreshold; QSpinBox *audioVolumeThreshold;
QDoubleSpinBox *duration;
VolControl *volMeter; VolControl *volMeter;
QLabel *whenLabel;
QLabel *aboveLabel;
QLabel *switchLabel;
QLabel *usingLabel;
AudioSwitch *switchData; AudioSwitch *switchData;
}; };

View File

@@ -6,6 +6,7 @@ constexpr auto exe_func = 3;
constexpr auto default_priority_3 = exe_func; constexpr auto default_priority_3 = exe_func;
struct ExecutableSwitch : SceneSwitcherEntry { struct ExecutableSwitch : SceneSwitcherEntry {
static bool pause;
QString exe = ""; QString exe = "";
bool inFocus = false; bool inFocus = false;
@@ -40,9 +41,5 @@ private:
QComboBox *processes; QComboBox *processes;
QCheckBox *requiresFocus; QCheckBox *requiresFocus;
QLabel *whenLabel;
QLabel *switchLabel;
QLabel *usingLabel;
ExecutableSwitch *switchData; ExecutableSwitch *switchData;
}; };

View File

@@ -1,33 +1,78 @@
#pragma once #pragma once
#include "switch-generic.hpp" #include "switch-generic.hpp"
#include <QPlainTextEdit>
#include <obs-module.h>
constexpr auto read_file_func = 0; constexpr auto read_file_func = 0;
constexpr auto default_priority_0 = read_file_func; constexpr auto default_priority_0 = read_file_func;
typedef enum {
LOCAL,
REMOTE,
} file_type;
struct FileSwitch : SceneSwitcherEntry { struct FileSwitch : SceneSwitcherEntry {
std::string file; static bool pause;
std::string text; std::string file = obs_module_text("AdvSceneSwitcher.enterPath");
std::string text = obs_module_text("AdvSceneSwitcher.enterText");
bool remote = false; bool remote = false;
bool useRegex = false; bool useRegex = false;
bool useTime = false; bool useTime = false;
bool onlyMatchIfChanged = false;
QDateTime lastMod; QDateTime lastMod;
size_t lastHash = 0;
const char *getType() { return "file"; } const char *getType() { return "file"; }
inline FileSwitch(){};
inline FileSwitch(OBSWeakSource scene_, OBSWeakSource transition_, inline FileSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
const char *file_, const char *text_, bool remote_, const char *file_, const char *text_, bool remote_,
bool useRegex_, bool useTime_) bool useRegex_, bool useTime_,
bool onlyMatchIfChanged_)
: SceneSwitcherEntry(scene_, transition_), : SceneSwitcherEntry(scene_, transition_),
file(file_), file(file_),
text(text_), text(text_),
remote(remote_), remote(remote_),
useRegex(useRegex_), useRegex(useRegex_),
useTime(useTime_), useTime(useTime_),
onlyMatchIfChanged(onlyMatchIfChanged_),
lastMod() lastMod()
{ {
} }
}; };
class FileSwitchWidget : public SwitchWidget {
Q_OBJECT
public:
FileSwitchWidget(FileSwitch *s);
FileSwitch *getSwitchData();
void setSwitchData(FileSwitch *s);
static void swapSwitchData(FileSwitchWidget *as1,
FileSwitchWidget *as2);
private slots:
void FileTypeChanged(int index);
void FilePathChanged();
void MatchTextChanged();
void UseRegexChanged(int state);
void CheckModificationDateChanged(int state);
void CheckFileContentChanged(int state);
void BrowseButtonClicked();
private:
QComboBox *fileType;
QLineEdit *filePath;
QPushButton *browseButton;
QPlainTextEdit *matchText;
QCheckBox *useRegex;
QCheckBox *checkModificationDate;
QCheckBox *checkFileContent;
FileSwitch *switchData;
};
struct FileIOData { struct FileIOData {
bool readEnabled = false; bool readEnabled = false;
std::string readPath; std::string readPath;
@@ -39,4 +84,4 @@ static inline QString MakeFileSwitchName(const QString &scene,
const QString &transition, const QString &transition,
const QString &fileName, const QString &fileName,
const QString &text, bool useRegex, const QString &text, bool useRegex,
bool useTime); bool useTime, bool onlyMatchIfChanged);

View File

@@ -6,6 +6,7 @@ constexpr auto idle_func = 2;
constexpr auto default_priority_2 = idle_func; constexpr auto default_priority_2 = idle_func;
struct IdleData : SceneSwitcherEntry { struct IdleData : SceneSwitcherEntry {
static bool pause;
bool idleEnable = false; bool idleEnable = false;
int time = default_idle_time; int time = default_idle_time;
bool alreadySwitched = false; bool alreadySwitched = false;

View File

@@ -13,6 +13,7 @@ typedef enum {
} time_restriction; } time_restriction;
struct MediaSwitch : SceneSwitcherEntry { struct MediaSwitch : SceneSwitcherEntry {
static bool pause;
OBSWeakSource source = nullptr; OBSWeakSource source = nullptr;
obs_media_state state = OBS_MEDIA_STATE_NONE; obs_media_state state = OBS_MEDIA_STATE_NONE;
bool anyState = false; bool anyState = false;
@@ -22,8 +23,8 @@ struct MediaSwitch : SceneSwitcherEntry {
// trigger scene change only once even if media state might trigger repeatedly // trigger scene change only once even if media state might trigger repeatedly
bool matched = false; bool matched = false;
std::atomic<bool> stopped = false; std::atomic_bool stopped = {false};
std::atomic<bool> ended = false; std::atomic_bool ended = {false};
// workaround to enable use of "ended" to specify end of VLC playlist // workaround to enable use of "ended" to specify end of VLC playlist
bool previousStateEnded = false; bool previousStateEnded = false;
@@ -70,16 +71,10 @@ private slots:
void TimeChanged(int time); void TimeChanged(int time);
private: private:
QComboBox *meidaSources; QComboBox *mediaSources;
QComboBox *states; QComboBox *states;
QComboBox *timeRestrictions; QComboBox *timeRestrictions;
QSpinBox *time; QSpinBox *time;
QLabel *whenLabel;
QLabel *stateLabel;
QLabel *andLabel;
QLabel *switchLabel;
QLabel *usingLabel;
MediaSwitch *switchData; MediaSwitch *switchData;
}; };

View File

@@ -0,0 +1,64 @@
#pragma once
#include "switch-generic.hpp"
enum class PauseType {
Scene,
Window,
};
enum class PauseTarget {
All,
Transition,
Window,
Executable,
Region,
Media,
File,
Random,
Time,
Idle,
Sequence,
Audio,
};
struct PauseEntry : SceneSwitcherEntry {
PauseType pauseType = PauseType::Scene;
PauseTarget pauseTarget = PauseTarget::All;
std::string window = "";
const char *getType() { return "pause"; }
bool valid();
inline PauseEntry(){};
inline PauseEntry(OBSWeakSource scene_, PauseType pauseType_,
PauseTarget pauseTarget_, const std::string &window_)
: SceneSwitcherEntry(scene_, nullptr),
pauseType(pauseType_),
pauseTarget(pauseTarget_),
window(window_)
{
}
};
class PauseEntryWidget : public SwitchWidget {
Q_OBJECT
public:
PauseEntryWidget(PauseEntry *s);
PauseEntry *getSwitchData();
void setSwitchData(PauseEntry *s);
static void swapSwitchData(PauseEntryWidget *s1, PauseEntryWidget *s2);
private slots:
void PauseTypeChanged(int index);
void PauseTargetChanged(int index);
void WindowChanged(const QString &text);
private:
QComboBox *pauseTypes;
QComboBox *pauseTargets;
QComboBox *windows;
PauseEntry *switchData;
};

View File

@@ -2,6 +2,7 @@
#include "switch-generic.hpp" #include "switch-generic.hpp"
struct RandomSwitch : SceneSwitcherEntry { struct RandomSwitch : SceneSwitcherEntry {
static bool pause;
double delay = 0.0; double delay = 0.0;
const char *getType() { return "random"; } const char *getType() { return "random"; }
@@ -31,9 +32,5 @@ private slots:
private: private:
QDoubleSpinBox *delay; QDoubleSpinBox *delay;
QLabel *switchLabel;
QLabel *usingLabel;
QLabel *forLabel;
RandomSwitch *switchData; RandomSwitch *switchData;
}; };

View File

@@ -6,6 +6,7 @@ constexpr auto screen_region_func = 4;
constexpr auto default_priority_4 = screen_region_func; constexpr auto default_priority_4 = screen_region_func;
struct ScreenRegionSwitch : SceneSwitcherEntry { struct ScreenRegionSwitch : SceneSwitcherEntry {
static bool pause;
int minX = 0, minY = 0, maxX = 0, maxY = 0; int minX = 0, minY = 0, maxX = 0, maxY = 0;
const char *getType() { return "region"; } const char *getType() { return "region"; }
@@ -51,11 +52,6 @@ private:
QFrame helperFrame; QFrame helperFrame;
QLabel *cursorLabel;
QLabel *xLabel;
QLabel *switchLabel;
QLabel *usingLabel;
ScreenRegionSwitch *switchData; ScreenRegionSwitch *switchData;
void drawFrame(); void drawFrame();

View File

@@ -11,6 +11,7 @@ typedef enum {
} delay_units; } delay_units;
struct SceneSequenceSwitch : SceneSwitcherEntry { struct SceneSequenceSwitch : SceneSwitcherEntry {
static bool pause;
OBSWeakSource startScene = nullptr; OBSWeakSource startScene = nullptr;
double delay = 0; double delay = 0;
int delayMultiplier = 1; int delayMultiplier = 1;
@@ -55,10 +56,5 @@ private:
QComboBox *delayUnits; QComboBox *delayUnits;
QComboBox *startScenes; QComboBox *startScenes;
QLabel *whenLabel;
QLabel *switchLabel;
QLabel *afterLabel;
QLabel *usingLabel;
SceneSequenceSwitch *switchData; SceneSequenceSwitch *switchData;
}; };

View File

@@ -19,8 +19,9 @@ typedef enum {
} timeTrigger; } timeTrigger;
struct TimeSwitch : SceneSwitcherEntry { struct TimeSwitch : SceneSwitcherEntry {
static bool pause;
timeTrigger trigger = ANY_DAY; timeTrigger trigger = ANY_DAY;
QTime time = QTime(); QTime time = QTime(0, 0);
const char *getType() { return "time"; } const char *getType() { return "time"; }
@@ -53,9 +54,5 @@ private:
QComboBox *triggers; QComboBox *triggers;
QTimeEdit *time; QTimeEdit *time;
QLabel *atLabel;
QLabel *switchLabel;
QLabel *usingLabel;
TimeSwitch *switchData; TimeSwitch *switchData;
}; };

View File

@@ -17,6 +17,7 @@ struct SceneTransition : SceneSwitcherEntry {
}; };
struct DefaultSceneTransition : SceneSwitcherEntry { struct DefaultSceneTransition : SceneSwitcherEntry {
static bool pause;
const char *getType() { return "def_transition"; } const char *getType() { return "def_transition"; }
@@ -45,10 +46,6 @@ private slots:
private: private:
QComboBox *scenes2; QComboBox *scenes2;
QLabel *switchLabel;
QLabel *toLabel;
QLabel *usingLabel;
SceneTransition *switchData; SceneTransition *switchData;
}; };
@@ -64,8 +61,5 @@ public:
DefTransitionSwitchWidget *s2); DefTransitionSwitchWidget *s2);
private: private:
QLabel *whenLabel;
QLabel *switchLabel;
DefaultSceneTransition *switchData; DefaultSceneTransition *switchData;
}; };

View File

@@ -5,6 +5,7 @@ constexpr auto window_title_func = 5;
constexpr auto default_priority_5 = window_title_func; constexpr auto default_priority_5 = window_title_func;
struct WindowSwitch : SceneSwitcherEntry { struct WindowSwitch : SceneSwitcherEntry {
static bool pause;
std::string window = ""; std::string window = "";
bool fullscreen = false; bool fullscreen = false;
bool maximized = false; bool maximized = false;

View File

@@ -12,6 +12,7 @@
#include "switch-file.hpp" #include "switch-file.hpp"
#include "switch-idle.hpp" #include "switch-idle.hpp"
#include "switch-media.hpp" #include "switch-media.hpp"
#include "switch-pause.hpp"
#include "switch-random.hpp" #include "switch-random.hpp"
#include "switch-screen-region.hpp" #include "switch-screen-region.hpp"
#include "switch-time.hpp" #include "switch-time.hpp"
@@ -73,10 +74,6 @@ struct SwitcherData {
std::deque<ScreenRegionSwitch> screenRegionSwitches; std::deque<ScreenRegionSwitch> screenRegionSwitches;
std::vector<OBSWeakSource> pauseScenesSwitches;
std::vector<std::string> pauseWindowsSwitches;
std::vector<std::string> ignoreWindowsSwitches; std::vector<std::string> ignoreWindowsSwitches;
std::deque<SceneSequenceSwitch> sceneSequenceSwitches; std::deque<SceneSequenceSwitch> sceneSequenceSwitches;
@@ -86,7 +83,7 @@ struct SwitcherData {
IdleData idleData; IdleData idleData;
FileIOData fileIO; FileIOData fileIO;
std::vector<FileSwitch> fileSwitches; std::deque<FileSwitch> fileSwitches;
CURL *curl = nullptr; CURL *curl = nullptr;
std::deque<ExecutableSwitch> executableSwitches; std::deque<ExecutableSwitch> executableSwitches;
@@ -105,6 +102,8 @@ struct SwitcherData {
std::deque<MediaSwitch> mediaSwitches; std::deque<MediaSwitch> mediaSwitches;
std::deque<PauseEntry> pauseEntries;
std::deque<TimeSwitch> timeSwitches; std::deque<TimeSwitch> timeSwitches;
QDateTime liveTime; QDateTime liveTime;
@@ -156,6 +155,7 @@ struct SwitcherData {
bool sceneChangedDuringWait(); bool sceneChangedDuringWait();
bool prioFuncsValid(); bool prioFuncsValid();
void writeSceneInfoToFile(); void writeSceneInfoToFile();
void writeToStatusFile(QString status);
void autoStopStreamAndRecording(); void autoStopStreamAndRecording();
void autoStartStreamRecording(); void autoStartStreamRecording();
bool checkPause(); bool checkPause();
@@ -206,6 +206,7 @@ struct SwitcherData {
void loadWindowTitleSwitches(obs_data_t *obj); void loadWindowTitleSwitches(obs_data_t *obj);
void loadScreenRegionSwitches(obs_data_t *obj); void loadScreenRegionSwitches(obs_data_t *obj);
void loadPauseSwitches(obs_data_t *obj); void loadPauseSwitches(obs_data_t *obj);
void loadOldPauseSwitches(obs_data_t *obj);
void loadSceneSequenceSwitches(obs_data_t *obj); void loadSceneSequenceSwitches(obs_data_t *obj);
void loadSceneTransitions(obs_data_t *obj); void loadSceneTransitions(obs_data_t *obj);
void loadIdleSwitches(obs_data_t *obj); void loadIdleSwitches(obs_data_t *obj);

View File

@@ -1,6 +1,12 @@
#pragma once #pragma once
#include <obs.hpp>
#include <QString> #include <QString>
#include <QLayout>
#include <QLabel>
#include <unordered_map>
#include <obs.hpp>
#include <obs-module.h>
#include <obs-frontend-api.h> #include <obs-frontend-api.h>
static inline bool WeakSourceValid(obs_weak_source_t *ws) static inline bool WeakSourceValid(obs_weak_source_t *ws)
@@ -82,3 +88,64 @@ static inline OBSWeakSource GetWeakTransitionByQString(const QString &name)
{ {
return GetWeakTransitionByName(name.toUtf8().constData()); return GetWeakTransitionByName(name.toUtf8().constData());
} }
static inline std::string
getNextDelim(std::string text,
std::unordered_map<std::string, QWidget *> placeholders)
{
size_t pos = std::string::npos;
std::string res = "";
for (const auto &ph : placeholders) {
size_t newPos = text.find(ph.first);
if (newPos <= pos) {
pos = newPos;
res = ph.first;
}
}
if (pos == std::string::npos)
return "";
return res;
}
/**
* Populate layout with labels and widgets based on provided text
*
* @param text Text based on which labels are generated and widgets are placed.
* @param layout Layout in which the widgets and labels will be placed.
* @param placeholders Map containing a mapping of placeholder strings to widgets.
* @param addStretch Add addStretch() to layout.
*/
static inline void
placeWidgets(std::string text, QBoxLayout *layout,
std::unordered_map<std::string, QWidget *> placeholders,
bool addStretch = true)
{
std::vector<std::pair<std::string, QWidget *>> labelsWidgetsPairs;
std::string delim = getNextDelim(text, placeholders);
while (delim != "") {
size_t pos = text.find(delim);
if (pos != std::string::npos) {
labelsWidgetsPairs.emplace_back(text.substr(0, pos),
placeholders[delim]);
text.erase(0, pos + delim.length());
}
delim = getNextDelim(text, placeholders);
}
if (text != "") {
labelsWidgetsPairs.emplace_back(text, nullptr);
}
for (auto &lw : labelsWidgetsPairs) {
if (lw.first != "")
layout->addWidget(new QLabel(lw.first.c_str()));
if (lw.second)
layout->addWidget(lw.second);
}
if (addStretch)
layout->addStretch();
}

View File

@@ -47,14 +47,17 @@ void startStopToggleHotkeyFunc(void *data, obs_hotkey_id id,
void registerHotkeys() void registerHotkeys()
{ {
switcher->startHotkey = obs_hotkey_register_frontend( switcher->startHotkey = obs_hotkey_register_frontend(
"startSwitcherHotkey", "Start the Advanced Scene Switcher", "startSwitcherHotkey",
obs_module_text("AdvSceneSwitcher.hotkey.startSwitcherHotkey"),
startHotkeyFunc, NULL); startHotkeyFunc, NULL);
switcher->stopHotkey = obs_hotkey_register_frontend( switcher->stopHotkey = obs_hotkey_register_frontend(
"stopSwitcherHotkey", "Stop the Advanced Scene Switcher", "stopSwitcherHotkey",
obs_module_text("AdvSceneSwitcher.hotkey.stopSwitcherHotkey"),
stopHotkeyFunc, NULL); stopHotkeyFunc, NULL);
switcher->toggleHotkey = obs_hotkey_register_frontend( switcher->toggleHotkey = obs_hotkey_register_frontend(
"startStopToggleSwitcherHotkey", "startStopToggleSwitcherHotkey",
"Toggle Start/Stop for the Advanced Scene Switcher", obs_module_text(
"AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey"),
startStopToggleHotkeyFunc, NULL); startStopToggleHotkeyFunc, NULL);
switcher->hotkeysRegistered = true; switcher->hotkeysRegistered = true;

View File

@@ -2,22 +2,17 @@
#include "headers/volume-control.hpp" #include "headers/volume-control.hpp"
#include "headers/utility.hpp" #include "headers/utility.hpp"
bool AudioSwitch::pause = false;
static QMetaObject::Connection addPulse; static QMetaObject::Connection addPulse;
void AdvSceneSwitcher::on_audioAdd_clicked() void AdvSceneSwitcher::on_audioAdd_clicked()
{ {
ui->audioAdd->disconnect(addPulse);
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->audioSwitches.emplace_back(); switcher->audioSwitches.emplace_back();
QListWidgetItem *item; listAddClicked(ui->audioSwitches,
item = new QListWidgetItem(ui->audioSwitches); new AudioSwitchWidget(&switcher->audioSwitches.back()),
ui->audioSwitches->addItem(item); ui->audioAdd, &addPulse);
AudioSwitchWidget *sw =
new AudioSwitchWidget(&switcher->audioSwitches.back());
item->setSizeHint(sw->minimumSizeHint());
ui->audioSwitches->setItemWidget(item, sw);
} }
void AdvSceneSwitcher::on_audioRemove_clicked() void AdvSceneSwitcher::on_audioRemove_clicked()
@@ -80,7 +75,7 @@ void AdvSceneSwitcher::on_audioDown_clicked()
void SwitcherData::checkAudioSwitch(bool &match, OBSWeakSource &scene, void SwitcherData::checkAudioSwitch(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition) OBSWeakSource &transition)
{ {
if (audioSwitches.size() == 0) if (AudioSwitch::pause)
return; return;
for (AudioSwitch &s : audioSwitches) { for (AudioSwitch &s : audioSwitches) {
@@ -92,10 +87,26 @@ void SwitcherData::checkAudioSwitch(bool &match, OBSWeakSource &scene,
obs_source_release(as); obs_source_release(as);
// peak will have a value from -60 db to 0 db // peak will have a value from -60 db to 0 db
bool volumeThresholdreached = ((double)s.peak + 60) * 1.7 > bool volumeThresholdreached = false;
s.volumeThreshold;
if (volumeThresholdreached && audioActive) { if (s.condition == ABOVE)
volumeThresholdreached = ((double)s.peak + 60) * 1.7 >
s.volumeThreshold;
else
volumeThresholdreached = ((double)s.peak + 60) * 1.7 <
s.volumeThreshold;
if (volumeThresholdreached) {
s.matchCount++;
} else {
s.matchCount = 0;
}
bool durationReached =
(s.matchCount * (unsigned int)interval) / 1000.0 >=
s.duration;
if (volumeThresholdreached && durationReached && audioActive) {
scene = (s.usePreviousScene) ? previousScene : s.scene; scene = (s.usePreviousScene) ? previousScene : s.scene;
transition = s.transition; transition = s.transition;
match = true; match = true;
@@ -136,6 +147,8 @@ void SwitcherData::saveAudioSwitches(obs_data_t *obj)
audioSourceName); audioSourceName);
obs_data_set_int(array_obj, "volume", obs_data_set_int(array_obj, "volume",
s.volumeThreshold); s.volumeThreshold);
obs_data_set_int(array_obj, "condition", s.condition);
obs_data_set_double(array_obj, "duration", s.duration);
obs_data_array_push_back(audioArray, array_obj); obs_data_array_push_back(audioArray, array_obj);
} }
obs_source_release(sceneSource); obs_source_release(sceneSource);
@@ -164,12 +177,15 @@ void SwitcherData::loadAudioSwitches(obs_data_t *obj)
const char *audioSource = const char *audioSource =
obs_data_get_string(array_obj, "audioSource"); obs_data_get_string(array_obj, "audioSource");
int vol = obs_data_get_int(array_obj, "volume"); int vol = obs_data_get_int(array_obj, "volume");
audioCondition condition = (audioCondition)obs_data_get_int(
array_obj, "condition");
double duration = obs_data_get_double(array_obj, "duration");
switcher->audioSwitches.emplace_back( switcher->audioSwitches.emplace_back(
GetWeakSourceByName(scene), GetWeakSourceByName(scene),
GetWeakTransitionByName(transition), GetWeakTransitionByName(transition),
GetWeakSourceByName(audioSource), vol, GetWeakSourceByName(audioSource), vol, condition,
(strcmp(scene, previous_scene_name) == 0)); duration, (strcmp(scene, previous_scene_name) == 0));
obs_data_release(array_obj); obs_data_release(array_obj);
} }
@@ -235,10 +251,13 @@ bool AudioSwitch::valid()
AudioSwitch::AudioSwitch(OBSWeakSource scene_, OBSWeakSource transition_, AudioSwitch::AudioSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
OBSWeakSource audioSource_, int volumeThreshold_, OBSWeakSource audioSource_, int volumeThreshold_,
audioCondition condition_, double duration_,
bool usePreviousScene_) bool usePreviousScene_)
: SceneSwitcherEntry(scene_, transition_, usePreviousScene_), : SceneSwitcherEntry(scene_, transition_, usePreviousScene_),
audioSource(audioSource_), audioSource(audioSource_),
volumeThreshold(volumeThreshold_) volumeThreshold(volumeThreshold_),
condition(condition_),
duration(duration_)
{ {
volmeter = obs_volmeter_create(OBS_FADER_LOG); volmeter = obs_volmeter_create(OBS_FADER_LOG);
obs_volmeter_add_callback(volmeter, setVolumeLevel, this); obs_volmeter_add_callback(volmeter, setVolumeLevel, this);
@@ -255,7 +274,9 @@ AudioSwitch::AudioSwitch(const AudioSwitch &other)
: SceneSwitcherEntry(other.scene, other.transition, : SceneSwitcherEntry(other.scene, other.transition,
other.usePreviousScene), other.usePreviousScene),
audioSource(other.audioSource), audioSource(other.audioSource),
volumeThreshold(other.volumeThreshold) volumeThreshold(other.volumeThreshold),
condition(other.condition),
duration(other.duration)
{ {
volmeter = obs_volmeter_create(OBS_FADER_LOG); volmeter = obs_volmeter_create(OBS_FADER_LOG);
obs_volmeter_add_callback(volmeter, setVolumeLevel, this); obs_volmeter_add_callback(volmeter, setVolumeLevel, this);
@@ -273,6 +294,8 @@ AudioSwitch::AudioSwitch(AudioSwitch &&other)
other.usePreviousScene), other.usePreviousScene),
audioSource(other.audioSource), audioSource(other.audioSource),
volumeThreshold(other.volumeThreshold), volumeThreshold(other.volumeThreshold),
condition(other.condition),
duration(other.duration),
volmeter(other.volmeter) volmeter(other.volmeter)
{ {
other.volmeter = nullptr; other.volmeter = nullptr;
@@ -313,16 +336,28 @@ void swap(AudioSwitch &first, AudioSwitch &second)
std::swap(first.usePreviousScene, second.usePreviousScene); std::swap(first.usePreviousScene, second.usePreviousScene);
std::swap(first.audioSource, second.audioSource); std::swap(first.audioSource, second.audioSource);
std::swap(first.volumeThreshold, second.volumeThreshold); std::swap(first.volumeThreshold, second.volumeThreshold);
std::swap(first.condition, second.condition);
std::swap(first.duration, second.duration);
std::swap(first.peak, second.peak); std::swap(first.peak, second.peak);
std::swap(first.volmeter, second.volmeter); std::swap(first.volmeter, second.volmeter);
first.resetVolmeter(); first.resetVolmeter();
second.resetVolmeter(); second.resetVolmeter();
} }
void populateConditionSelection(QComboBox *list)
{
list->addItem(
obs_module_text("AdvSceneSwitcher.audioTab.condition.above"));
list->addItem(
obs_module_text("AdvSceneSwitcher.audioTab.condition.below"));
}
AudioSwitchWidget::AudioSwitchWidget(AudioSwitch *s) : SwitchWidget(s) AudioSwitchWidget::AudioSwitchWidget(AudioSwitch *s) : SwitchWidget(s)
{ {
audioSources = new QComboBox(); audioSources = new QComboBox();
condition = new QComboBox();
audioVolumeThreshold = new QSpinBox(); audioVolumeThreshold = new QSpinBox();
duration = new QDoubleSpinBox();
obs_source_t *soruce = nullptr; obs_source_t *soruce = nullptr;
if (s) if (s)
@@ -330,46 +365,49 @@ AudioSwitchWidget::AudioSwitchWidget(AudioSwitch *s) : SwitchWidget(s)
volMeter = new VolControl(soruce); volMeter = new VolControl(soruce);
obs_source_release(soruce); obs_source_release(soruce);
whenLabel = new QLabel("When the volume of");
aboveLabel = new QLabel("is above");
switchLabel = new QLabel("switch to");
usingLabel = new QLabel("using");
audioVolumeThreshold->setSuffix("%"); audioVolumeThreshold->setSuffix("%");
audioVolumeThreshold->setMaximum(100); audioVolumeThreshold->setMaximum(100);
audioVolumeThreshold->setMinimum(0); audioVolumeThreshold->setMinimum(0);
duration->setMinimum(0.0);
duration->setMaximum(99.000000);
duration->setSuffix("s");
QWidget::connect(volMeter->GetSlider(), SIGNAL(valueChanged(int)), QWidget::connect(volMeter->GetSlider(), SIGNAL(valueChanged(int)),
audioVolumeThreshold, SLOT(setValue(int))); audioVolumeThreshold, SLOT(setValue(int)));
QWidget::connect(audioVolumeThreshold, SIGNAL(valueChanged(int)), QWidget::connect(audioVolumeThreshold, SIGNAL(valueChanged(int)),
volMeter->GetSlider(), SLOT(setValue(int))); volMeter->GetSlider(), SLOT(setValue(int)));
QWidget::connect(audioVolumeThreshold, SIGNAL(valueChanged(int)), this, QWidget::connect(audioVolumeThreshold, SIGNAL(valueChanged(int)), this,
SLOT(VolumeThresholdChanged(int))); SLOT(VolumeThresholdChanged(int)));
QWidget::connect(condition, SIGNAL(currentIndexChanged(int)), this,
SLOT(ConditionChanged(int)));
QWidget::connect(duration, SIGNAL(valueChanged(double)), this,
SLOT(DurationChanged(double)));
QWidget::connect(audioSources, QWidget::connect(audioSources,
SIGNAL(currentTextChanged(const QString &)), this, SIGNAL(currentTextChanged(const QString &)), this,
SLOT(SourceChanged(const QString &))); SLOT(SourceChanged(const QString &)));
AdvSceneSwitcher::populateAudioSelection(audioSources); AdvSceneSwitcher::populateAudioSelection(audioSources);
populateConditionSelection(condition);
if (s) { if (s) {
audioSources->setCurrentText( audioSources->setCurrentText(
GetWeakSourceName(s->audioSource).c_str()); GetWeakSourceName(s->audioSource).c_str());
audioVolumeThreshold->setValue(s->volumeThreshold); audioVolumeThreshold->setValue(s->volumeThreshold);
condition->setCurrentIndex(s->condition);
duration->setValue(s->duration);
} }
setStyleSheet("* { background-color: transparent; }");
QHBoxLayout *switchLayout = new QHBoxLayout; QHBoxLayout *switchLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
switchLayout->addWidget(whenLabel); {"{{audioSources}}", audioSources},
switchLayout->addWidget(audioSources); {"{{volumeWidget}}", audioVolumeThreshold},
switchLayout->addWidget(aboveLabel); {"{{condition}}", condition},
switchLayout->addWidget(audioVolumeThreshold); {"{{duration}}", duration},
switchLayout->addWidget(switchLabel); {"{{scenes}}", scenes},
switchLayout->addWidget(scenes); {"{{transitions}}", transitions}};
switchLayout->addWidget(usingLabel); placeWidgets(obs_module_text("AdvSceneSwitcher.audioTab.entry"),
switchLayout->addWidget(transitions); switchLayout, widgetPlaceholders);
switchLayout->addStretch();
QVBoxLayout *mainLayout = new QVBoxLayout; QVBoxLayout *mainLayout = new QVBoxLayout;
@@ -440,3 +478,19 @@ void AudioSwitchWidget::VolumeThresholdChanged(int vol)
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switchData->volumeThreshold = vol; switchData->volumeThreshold = vol;
} }
void AudioSwitchWidget::ConditionChanged(int cond)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->condition = (audioCondition)cond;
}
void AudioSwitchWidget::DurationChanged(double dur)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->duration = dur;
}

View File

@@ -1,22 +1,18 @@
#include "headers/advanced-scene-switcher.hpp" #include "headers/advanced-scene-switcher.hpp"
#include "headers/utility.hpp" #include "headers/utility.hpp"
bool ExecutableSwitch::pause = false;
static QMetaObject::Connection addPulse; static QMetaObject::Connection addPulse;
void AdvSceneSwitcher::on_executableAdd_clicked() void AdvSceneSwitcher::on_executableAdd_clicked()
{ {
ui->executableAdd->disconnect(addPulse);
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->executableSwitches.emplace_back(); switcher->executableSwitches.emplace_back();
QListWidgetItem *item; listAddClicked(ui->executables,
item = new QListWidgetItem(ui->executables); new ExecutableSwitchWidget(
ui->executables->addItem(item); &switcher->executableSwitches.back()),
ExecutableSwitchWidget *sw = new ExecutableSwitchWidget( ui->executableAdd, &addPulse);
&switcher->executableSwitches.back());
item->setSizeHint(sw->minimumSizeHint());
ui->executables->setItemWidget(item, sw);
} }
void AdvSceneSwitcher::on_executableRemove_clicked() void AdvSceneSwitcher::on_executableRemove_clicked()
@@ -79,6 +75,9 @@ void AdvSceneSwitcher::on_executableDown_clicked()
void SwitcherData::checkExeSwitch(bool &match, OBSWeakSource &scene, void SwitcherData::checkExeSwitch(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition) OBSWeakSource &transition)
{ {
if (executableSwitches.size() == 0 || ExecutableSwitch::pause)
return;
std::string title; std::string title;
QStringList runningProcesses; QStringList runningProcesses;
bool ignored = false; bool ignored = false;
@@ -206,11 +205,8 @@ ExecutableSwitchWidget::ExecutableSwitchWidget(ExecutableSwitch *s)
: SwitchWidget(s, false) : SwitchWidget(s, false)
{ {
processes = new QComboBox(); processes = new QComboBox();
requiresFocus = new QCheckBox("only if focused"); requiresFocus = new QCheckBox(obs_module_text(
"AdvSceneSwitcher.executableTab.requiresFocus"));
whenLabel = new QLabel("When");
switchLabel = new QLabel("is running switch to");
usingLabel = new QLabel("using");
QWidget::connect(processes, SIGNAL(currentTextChanged(const QString &)), QWidget::connect(processes, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(ProcessChanged(const QString &))); this, SLOT(ProcessChanged(const QString &)));
@@ -227,19 +223,14 @@ ExecutableSwitchWidget::ExecutableSwitchWidget(ExecutableSwitch *s)
requiresFocus->setChecked(s->inFocus); requiresFocus->setChecked(s->inFocus);
} }
setStyleSheet("* { background-color: transparent; }");
QHBoxLayout *mainLayout = new QHBoxLayout; QHBoxLayout *mainLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
mainLayout->addWidget(whenLabel); {"{{processes}}", processes},
mainLayout->addWidget(processes); {"{{requiresFocus}}", requiresFocus},
mainLayout->addWidget(switchLabel); {"{{scenes}}", scenes},
mainLayout->addWidget(scenes); {"{{transitions}}", transitions}};
mainLayout->addWidget(usingLabel); placeWidgets(obs_module_text("AdvSceneSwitcher.executableTab.entry"),
mainLayout->addWidget(transitions); mainLayout, widgetPlaceholders);
mainLayout->addWidget(requiresFocus);
mainLayout->addStretch();
setLayout(mainLayout); setLayout(mainLayout);
switchData = s; switchData = s;

View File

@@ -1,20 +1,24 @@
#include <QFileDialog> #include <QFileDialog>
#include <QTextStream> #include <QTextStream>
#include <QDateTime> #include <QDateTime>
#include <functional>
#include <curl/curl.h> #include <curl/curl.h>
#include "headers/advanced-scene-switcher.hpp" #include "headers/advanced-scene-switcher.hpp"
#include "headers/curl-helper.hpp" #include "headers/curl-helper.hpp"
#include "headers/utility.hpp" #include "headers/utility.hpp"
#define LOCAL_FILE_IDX 0 bool FileSwitch::pause = false;
#define REMOTE_FILE_IDX 1 static QMetaObject::Connection addPulse;
static std::hash<std::string> strHash;
void AdvSceneSwitcher::on_browseButton_clicked() void AdvSceneSwitcher::on_browseButton_clicked()
{ {
QString path = QFileDialog::getOpenFileName( QString path = QFileDialog::getOpenFileName(
this, tr("Select a file to write to ..."), QDir::currentPath(), this,
tr("Text files (*.txt)")); tr(obs_module_text("AdvSceneSwitcher.fileTab.selectWrite")),
QDir::currentPath(),
tr(obs_module_text("AdvSceneSwitcher.fileTab.textFileType")));
if (!path.isEmpty()) if (!path.isEmpty())
ui->writePathLineEdit->setText(path); ui->writePathLineEdit->setText(path);
} }
@@ -67,8 +71,10 @@ void AdvSceneSwitcher::on_writePathLineEdit_textChanged(const QString &text)
void AdvSceneSwitcher::on_browseButton_2_clicked() void AdvSceneSwitcher::on_browseButton_2_clicked()
{ {
QString path = QFileDialog::getOpenFileName( QString path = QFileDialog::getOpenFileName(
this, tr("Select a file to read from ..."), QDir::currentPath(), this,
tr("Any files (*.*)")); tr(obs_module_text("AdvSceneSwitcher.fileTab.selectRead")),
QDir::currentPath(),
tr(obs_module_text("AdvSceneSwitcher.fileTab.anyFileType")));
if (!path.isEmpty()) if (!path.isEmpty())
ui->readPathLineEdit->setText(path); ui->readPathLineEdit->setText(path);
} }
@@ -89,6 +95,19 @@ void SwitcherData::writeSceneInfoToFile()
obs_source_release(currentSource); obs_source_release(currentSource);
} }
void SwitcherData::writeToStatusFile(QString msg)
{
if (!fileIO.writeEnabled || fileIO.writePath.empty())
return;
QFile file(QString::fromStdString(fileIO.writePath));
if (file.open(QIODevice::ReadWrite)) {
QTextStream stream(&file);
stream << msg << endl;
}
file.close();
}
void SwitcherData::checkSwitchInfoFromFile(bool &match, OBSWeakSource &scene, void SwitcherData::checkSwitchInfoFromFile(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition) OBSWeakSource &transition)
{ {
@@ -148,37 +167,50 @@ bool compareIgnoringLineEnding(QString &s1, QString &s2)
QTextStream s1stream(&s1); QTextStream s1stream(&s1);
QTextStream s2stream(&s2); QTextStream s2stream(&s2);
while (!s1stream.atEnd() && !s2stream.atEnd()) { while (!s1stream.atEnd() || !s2stream.atEnd()) {
QString s1s = s1stream.readLine(); QString s1s = s1stream.readLine();
QString s2s = s2stream.readLine(); QString s2s = s2stream.readLine();
if (QString::compare(s1s, s2s, Qt::CaseSensitive) != 0) { if (s1s != s2s) {
return false; return false;
} }
} }
if (!s1stream.atEnd() && !s2stream.atEnd())
return false;
return true; return true;
} }
bool matchFileContent(QString &filedata, FileSwitch &s)
{
if (s.onlyMatchIfChanged) {
size_t newHash = strHash(filedata.toUtf8().constData());
if (newHash == s.lastHash)
return false;
s.lastHash = newHash;
}
if (s.useRegex) {
QRegExp rx(QString::fromStdString(s.text));
return rx.exactMatch(filedata);
}
QString text = QString::fromStdString(s.text);
return compareIgnoringLineEnding(text, filedata);
}
bool checkRemoteFileContent(FileSwitch &s) bool checkRemoteFileContent(FileSwitch &s)
{ {
std::string data = getRemoteData(s.file); std::string data = getRemoteData(s.file);
bool ret = false; QString qdata = QString::fromStdString(data);
if (s.useRegex) { return matchFileContent(qdata, s);
ret = QString::fromStdString(data).contains(
QRegularExpression(QString::fromStdString(s.text)));
return ret;
}
QString t = QString::fromStdString(s.text);
QString d = QString::fromStdString(data);
return compareIgnoringLineEnding(t, d);
} }
bool checkLocalFileContent(FileSwitch &s) bool checkLocalFileContent(FileSwitch &s)
{ {
bool equal = false;
QString t = QString::fromStdString(s.text); QString t = QString::fromStdString(s.text);
QFile file(QString::fromStdString(s.file)); QFile file(QString::fromStdString(s.file));
if (!file.open(QIODevice::ReadOnly)) if (s.file.empty() || !file.open(QIODevice::ReadOnly))
return false; return false;
if (s.useTime) { if (s.useTime) {
@@ -188,23 +220,23 @@ bool checkLocalFileContent(FileSwitch &s)
s.lastMod = newLastMod; s.lastMod = newLastMod;
} }
if (s.useRegex) { QString filedata = QTextStream(&file).readAll();
QTextStream in(&file); bool match = matchFileContent(filedata, s);
QRegExp rx(t);
equal = rx.exactMatch(in.readAll());
} else {
QTextStream in(&file);
QString filedata = in.readAll();
equal = compareIgnoringLineEnding(filedata, t);
}
file.close(); file.close();
return equal; return match;
} }
void SwitcherData::checkFileContent(bool &match, OBSWeakSource &scene, void SwitcherData::checkFileContent(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition) OBSWeakSource &transition)
{ {
if (FileSwitch::pause)
return;
for (FileSwitch &s : fileSwitches) { for (FileSwitch &s : fileSwitches) {
if (!s.initialized())
continue;
bool equal = false; bool equal = false;
if (s.remote) { if (s.remote) {
equal = checkRemoteFileContent(s); equal = checkRemoteFileContent(s);
@@ -224,83 +256,33 @@ void SwitcherData::checkFileContent(bool &match, OBSWeakSource &scene,
} }
} }
void AdvSceneSwitcher::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 AdvSceneSwitcher::on_fileType_currentIndexChanged(int idx)
{
if (idx == -1)
return;
if (idx == LOCAL_FILE_IDX) {
ui->browseButton_3->setDisabled(false);
ui->fileContentTimeCheckBox->setDisabled(false);
ui->remoteFileWarningLabel->hide();
}
if (idx == REMOTE_FILE_IDX) {
ui->browseButton_3->setDisabled(true);
ui->fileContentTimeCheckBox->setDisabled(true);
ui->remoteFileWarningLabel->show();
}
}
void AdvSceneSwitcher::on_fileAdd_clicked() void AdvSceneSwitcher::on_fileAdd_clicked()
{ {
QString sceneName = ui->fileScenes->currentText();
QString transitionName = ui->fileTransitions->currentText();
QString fileName = ui->filePathLineEdit->text();
QString text = ui->fileTextEdit->toPlainText();
bool remote = (ui->fileType->currentIndex() == REMOTE_FILE_IDX);
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);
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->fileSwitches.emplace_back(source, transition, switcher->fileSwitches.emplace_back();
fileName.toUtf8().constData(),
text.toUtf8().constData(), remote, listAddClicked(ui->fileSwitches,
useRegex, useTime); new FileSwitchWidget(&switcher->fileSwitches.back()),
ui->fileAdd, &addPulse);
} }
void AdvSceneSwitcher::on_fileRemove_clicked() void AdvSceneSwitcher::on_fileRemove_clicked()
{ {
QListWidgetItem *item = ui->fileScenesList->currentItem(); QListWidgetItem *item = ui->fileSwitches->currentItem();
if (!item) if (!item)
return; return;
int idx = ui->fileScenesList->currentRow();
if (idx == -1)
return;
{ {
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
int idx = ui->fileSwitches->currentRow();
auto &switches = switcher->fileSwitches; auto &switches = switcher->fileSwitches;
switches.erase(switches.begin() + idx); switches.erase(switches.begin() + idx);
} }
qDeleteAll(ui->fileScenesList->selectedItems());
delete item;
} }
void AdvSceneSwitcher::on_fileScenesList_currentRowChanged(int idx) void AdvSceneSwitcher::on_fileSwitches_currentRowChanged(int idx)
{ {
if (loading) if (loading)
return; return;
@@ -312,50 +294,47 @@ void AdvSceneSwitcher::on_fileScenesList_currentRowChanged(int idx)
if ((int)switcher->fileSwitches.size() <= idx) if ((int)switcher->fileSwitches.size() <= idx)
return; return;
FileSwitch s = switcher->fileSwitches[idx]; FileSwitch s = switcher->fileSwitches[idx];
std::string sceneName = GetWeakSourceName(s.scene);
std::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());
if (s.remote) if (s.remote)
ui->fileType->setCurrentIndex(REMOTE_FILE_IDX); ui->remoteFileWarningLabel->show();
else else
ui->fileType->setCurrentIndex(LOCAL_FILE_IDX); ui->remoteFileWarningLabel->hide();
ui->fileContentRegExCheckBox->setChecked(s.useRegex);
ui->fileContentTimeCheckBox->setChecked(s.useTime);
} }
void AdvSceneSwitcher::on_fileUp_clicked() void AdvSceneSwitcher::on_fileUp_clicked()
{ {
int index = ui->fileScenesList->currentRow(); int index = ui->fileSwitches->currentRow();
if (index != -1 && index != 0) { if (!listMoveUp(ui->fileSwitches))
ui->fileScenesList->insertItem( return;
index - 1, ui->fileScenesList->takeItem(index));
ui->fileScenesList->setCurrentRow(index - 1);
std::lock_guard<std::mutex> lock(switcher->m); FileSwitchWidget *s1 = (FileSwitchWidget *)ui->fileSwitches->itemWidget(
ui->fileSwitches->item(index));
FileSwitchWidget *s2 = (FileSwitchWidget *)ui->fileSwitches->itemWidget(
ui->fileSwitches->item(index - 1));
FileSwitchWidget::swapSwitchData(s1, s2);
iter_swap(switcher->fileSwitches.begin() + index, std::lock_guard<std::mutex> lock(switcher->m);
switcher->fileSwitches.begin() + index - 1);
} std::swap(switcher->fileSwitches[index],
switcher->fileSwitches[index - 1]);
} }
void AdvSceneSwitcher::on_fileDown_clicked() void AdvSceneSwitcher::on_fileDown_clicked()
{ {
int index = ui->fileScenesList->currentRow(); int index = ui->fileSwitches->currentRow();
if (index != -1 && index != ui->fileScenesList->count() - 1) {
ui->fileScenesList->insertItem(
index + 1, ui->fileScenesList->takeItem(index));
ui->fileScenesList->setCurrentRow(index + 1);
std::lock_guard<std::mutex> lock(switcher->m); if (!listMoveDown(ui->fileSwitches))
return;
iter_swap(switcher->fileSwitches.begin() + index, FileSwitchWidget *s1 = (FileSwitchWidget *)ui->fileSwitches->itemWidget(
switcher->fileSwitches.begin() + index + 1); ui->fileSwitches->item(index));
} FileSwitchWidget *s2 = (FileSwitchWidget *)ui->fileSwitches->itemWidget(
ui->fileSwitches->item(index + 1));
FileSwitchWidget::swapSwitchData(s1, s2);
std::lock_guard<std::mutex> lock(switcher->m);
std::swap(switcher->fileSwitches[index],
switcher->fileSwitches[index + 1]);
} }
void SwitcherData::saveFileSwitches(obs_data_t *obj) void SwitcherData::saveFileSwitches(obs_data_t *obj)
@@ -380,6 +359,8 @@ void SwitcherData::saveFileSwitches(obs_data_t *obj)
obs_data_set_bool(array_obj, "remote", s.remote); obs_data_set_bool(array_obj, "remote", s.remote);
obs_data_set_bool(array_obj, "useRegex", s.useRegex); obs_data_set_bool(array_obj, "useRegex", s.useRegex);
obs_data_set_bool(array_obj, "useTime", s.useTime); obs_data_set_bool(array_obj, "useTime", s.useTime);
obs_data_set_bool(array_obj, "onlyMatchIfChanged",
s.onlyMatchIfChanged);
obs_data_array_push_back(fileArray, array_obj); obs_data_array_push_back(fileArray, array_obj);
} }
obs_source_release(source); obs_source_release(source);
@@ -413,11 +394,13 @@ void SwitcherData::loadFileSwitches(obs_data_t *obj)
bool remote = obs_data_get_bool(array_obj, "remote"); bool remote = obs_data_get_bool(array_obj, "remote");
bool useRegex = obs_data_get_bool(array_obj, "useRegex"); bool useRegex = obs_data_get_bool(array_obj, "useRegex");
bool useTime = obs_data_get_bool(array_obj, "useTime"); bool useTime = obs_data_get_bool(array_obj, "useTime");
bool onlyMatchIfChanged =
obs_data_get_bool(array_obj, "onlyMatchIfChanged");
switcher->fileSwitches.emplace_back( switcher->fileSwitches.emplace_back(
GetWeakSourceByName(scene), GetWeakSourceByName(scene),
GetWeakTransitionByName(transition), file, text, remote, GetWeakTransitionByName(transition), file, text, remote,
useRegex, useTime); useRegex, useTime, onlyMatchIfChanged);
obs_data_release(array_obj); obs_data_release(array_obj);
} }
@@ -433,30 +416,27 @@ void SwitcherData::loadFileSwitches(obs_data_t *obj)
void AdvSceneSwitcher::setupFileTab() void AdvSceneSwitcher::setupFileTab()
{ {
populateSceneSelection(ui->fileScenes, false);
populateTransitionSelection(ui->fileTransitions);
ui->fileType->addItem("local");
ui->fileType->addItem("remote");
ui->remoteFileWarningLabel->setText( ui->remoteFileWarningLabel->setText(
"Note that the scene switcher will try to access the remote location every " + obs_module_text("AdvSceneSwitcher.fileTab.remoteFileWarning1") +
QString::number(switcher->interval) + "ms"); QString::number(switcher->interval) +
obs_module_text("AdvSceneSwitcher.fileTab.remoteFileWarning2"));
ui->remoteFileWarningLabel->hide();
if (switcher->curl) if (switcher->curl)
ui->libcurlWarning->setVisible(false); ui->libcurlWarning->setVisible(false);
for (auto &s : switcher->fileSwitches) { for (auto &s : switcher->fileSwitches) {
std::string sceneName = GetWeakSourceName(s.scene); QListWidgetItem *item;
std::string transitionName = GetWeakSourceName(s.transition); item = new QListWidgetItem(ui->fileSwitches);
QString listText = MakeFileSwitchName( ui->fileSwitches->addItem(item);
sceneName.c_str(), transitionName.c_str(), FileSwitchWidget *sw = new FileSwitchWidget(&s);
s.file.c_str(), s.text.c_str(), s.useRegex, s.useTime); item->setSizeHint(sw->minimumSizeHint());
ui->fileSwitches->setItemWidget(item, sw);
QListWidgetItem *item =
new QListWidgetItem(listText, ui->fileScenesList);
item->setData(Qt::UserRole, listText);
} }
if (switcher->fileSwitches.size() == 0)
addPulse = PulseWidget(ui->fileAdd, QColor(Qt::green));
ui->readPathLineEdit->setText( ui->readPathLineEdit->setText(
QString::fromStdString(switcher->fileIO.readPath.c_str())); QString::fromStdString(switcher->fileIO.readPath.c_str()));
ui->readFileCheckBox->setChecked(switcher->fileIO.readEnabled); ui->readFileCheckBox->setChecked(switcher->fileIO.readEnabled);
@@ -472,26 +452,173 @@ void AdvSceneSwitcher::setupFileTab()
} }
} }
static inline QString MakeFileSwitchName(const QString &scene, FileSwitchWidget::FileSwitchWidget(FileSwitch *s) : SwitchWidget(s, false)
const QString &transition,
const QString &fileName,
const QString &text, bool useRegex,
bool useTime)
{ {
QString switchName = QStringLiteral("Switch to ") + scene + fileType = new QComboBox();
QStringLiteral(" using ") + transition + filePath = new QLineEdit();
QStringLiteral(" if ") + fileName; browseButton =
if (useTime) new QPushButton(obs_module_text("AdvSceneSwitcher.browse"));
switchName += QStringLiteral(" was modified and"); browseButton->setStyleSheet("border:1px solid gray;");
switchName += QStringLiteral(" contains"); matchText = new QPlainTextEdit();
if (useRegex) useRegex = new QCheckBox(
switchName += QStringLiteral(" (RegEx): \n\""); obs_module_text("AdvSceneSwitcher.fileTab.useRegExp"));
else checkModificationDate = new QCheckBox(obs_module_text(
switchName += QStringLiteral(": \n\""); "AdvSceneSwitcher.fileTab.checkfileContentTime"));
if (text.length() > 30) checkFileContent = new QCheckBox(
switchName += text.left(27) + QStringLiteral("...\""); obs_module_text("AdvSceneSwitcher.fileTab.checkfileContent"));
else
switchName += text + QStringLiteral("\"");
return switchName; QWidget::connect(fileType, SIGNAL(currentIndexChanged(int)), this,
SLOT(FileTypeChanged(int)));
QWidget::connect(filePath, SIGNAL(editingFinished()), this,
SLOT(FilePathChanged()));
QWidget::connect(browseButton, SIGNAL(clicked()), this,
SLOT(BrowseButtonClicked()));
QWidget::connect(matchText, SIGNAL(textChanged()), this,
SLOT(MatchTextChanged()));
QWidget::connect(useRegex, SIGNAL(stateChanged(int)), this,
SLOT(UseRegexChanged(int)));
QWidget::connect(checkModificationDate, SIGNAL(stateChanged(int)), this,
SLOT(CheckModificationDateChanged(int)));
QWidget::connect(checkFileContent, SIGNAL(stateChanged(int)), this,
SLOT(CheckFileContentChanged(int)));
fileType->addItem(obs_module_text("AdvSceneSwitcher.fileTab.local"));
fileType->addItem(obs_module_text("AdvSceneSwitcher.fileTab.remote"));
if (s) {
if (s->remote)
fileType->setCurrentIndex(1);
else
fileType->setCurrentIndex(0);
filePath->setText(QString::fromStdString(s->file));
matchText->setPlainText(QString::fromStdString(s->text));
useRegex->setChecked(s->useRegex);
checkModificationDate->setChecked(s->useTime);
checkFileContent->setChecked(s->onlyMatchIfChanged);
}
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{fileType}}", fileType},
{"{{filePath}}", filePath},
{"{{browseButton}}", browseButton},
{"{{matchText}}", matchText},
{"{{useRegex}}", useRegex},
{"{{checkModificationDate}}", checkModificationDate},
{"{{checkFileContent}}", checkFileContent},
{"{{scenes}}", scenes},
{"{{transitions}}", transitions}};
QVBoxLayout *mainLayout = new QVBoxLayout;
QHBoxLayout *line1Layout = new QHBoxLayout;
QHBoxLayout *line2Layout = new QHBoxLayout;
QHBoxLayout *line3Layout = new QHBoxLayout;
placeWidgets(obs_module_text("AdvSceneSwitcher.fileTab.entry"),
line1Layout, widgetPlaceholders);
placeWidgets(obs_module_text("AdvSceneSwitcher.fileTab.entry2"),
line2Layout, widgetPlaceholders, false);
placeWidgets(obs_module_text("AdvSceneSwitcher.fileTab.entry3"),
line3Layout, widgetPlaceholders);
mainLayout->addLayout(line1Layout);
mainLayout->addLayout(line2Layout);
mainLayout->addLayout(line3Layout);
setLayout(mainLayout);
switchData = s;
loading = false;
}
FileSwitch *FileSwitchWidget::getSwitchData()
{
return switchData;
}
void FileSwitchWidget::setSwitchData(FileSwitch *s)
{
switchData = s;
}
void FileSwitchWidget::swapSwitchData(FileSwitchWidget *s1,
FileSwitchWidget *s2)
{
SwitchWidget::swapSwitchData(s1, s2);
FileSwitch *t = s1->getSwitchData();
s1->setSwitchData(s2->getSwitchData());
s2->setSwitchData(t);
}
void FileSwitchWidget::FileTypeChanged(int index)
{
if (loading || !switchData)
return;
if ((file_type)index == LOCAL) {
browseButton->setDisabled(false);
checkModificationDate->setDisabled(false);
} else {
browseButton->setDisabled(true);
checkModificationDate->setDisabled(true);
}
std::lock_guard<std::mutex> lock(switcher->m);
switchData->remote = (file_type)index == REMOTE;
}
void FileSwitchWidget::FilePathChanged()
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->file = filePath->text().toUtf8().constData();
}
void FileSwitchWidget::BrowseButtonClicked()
{
if (loading || !switchData)
return;
QString path = QFileDialog::getOpenFileName(
this,
tr(obs_module_text("AdvSceneSwitcher.fileTab.selectRead")),
QDir::currentPath(),
tr(obs_module_text("AdvSceneSwitcher.fileTab.anyFileType")));
if (path.isEmpty())
return;
filePath->setText(path);
FilePathChanged();
}
void FileSwitchWidget::MatchTextChanged()
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->text = matchText->toPlainText().toUtf8().constData();
}
void FileSwitchWidget::UseRegexChanged(int state)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->useRegex = state;
}
void FileSwitchWidget::CheckModificationDateChanged(int state)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->useTime = state;
}
void FileSwitchWidget::CheckFileContentChanged(int state)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->onlyMatchIfChanged = state;
} }

View File

@@ -30,6 +30,12 @@ SwitchWidget::SwitchWidget(SceneSwitcherEntry *s, bool usePreviousScene)
scenes = new QComboBox(); scenes = new QComboBox();
transitions = new QComboBox(); transitions = new QComboBox();
// Depending on selected OBS theme some widgets might have a different
// background color than the listwidget and might look out of place
setStyleSheet("QLabel { background-color: transparent; }\
QSlider { background-color: transparent; }\
QCheckBox { background-color: transparent; }");
QWidget::connect(scenes, SIGNAL(currentTextChanged(const QString &)), QWidget::connect(scenes, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(SceneChanged(const QString &))); this, SLOT(SceneChanged(const QString &)));
QWidget::connect(transitions, QWidget::connect(transitions,
@@ -41,7 +47,8 @@ SwitchWidget::SwitchWidget(SceneSwitcherEntry *s, bool usePreviousScene)
if (s) { if (s) {
if (s->usePreviousScene) if (s->usePreviousScene)
scenes->setCurrentText(previous_scene_name); scenes->setCurrentText(obs_module_text(
"AdvSceneSwitcher.selectPreviousScene"));
else else
scenes->setCurrentText( scenes->setCurrentText(
GetWeakSourceName(s->scene).c_str()); GetWeakSourceName(s->scene).c_str());
@@ -69,12 +76,18 @@ void SwitchWidget::swapSwitchData(SwitchWidget *s1, SwitchWidget *s2)
s2->setSwitchData(t); s2->setSwitchData(t);
} }
bool isPreviousScene(const QString &text)
{
return text.compare(obs_module_text(
"AdvSceneSwitcher.selectPreviousScene")) == 0;
}
void SwitchWidget::SceneChanged(const QString &text) void SwitchWidget::SceneChanged(const QString &text)
{ {
if (loading || !switchData) if (loading || !switchData)
return; return;
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switchData->usePreviousScene = text.compare(previous_scene_name) == 0; switchData->usePreviousScene = isPreviousScene(text);
if (switchData->usePreviousScene) if (switchData->usePreviousScene)
return; return;
switchData->scene = GetWeakSourceByQString(text); switchData->scene = GetWeakSourceByQString(text);

View File

@@ -3,10 +3,12 @@
#include "headers/advanced-scene-switcher.hpp" #include "headers/advanced-scene-switcher.hpp"
#include "headers/utility.hpp" #include "headers/utility.hpp"
bool IdleData::pause = false;
void SwitcherData::checkIdleSwitch(bool &match, OBSWeakSource &scene, void SwitcherData::checkIdleSwitch(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition) OBSWeakSource &transition)
{ {
if (!idleData.idleEnable) if (!idleData.idleEnable || IdleData::pause)
return; return;
std::string title; std::string title;
@@ -83,7 +85,9 @@ void AdvSceneSwitcher::UpdateIdleDataTransition(const QString &name)
void AdvSceneSwitcher::UpdateIdleDataScene(const QString &name) void AdvSceneSwitcher::UpdateIdleDataScene(const QString &name)
{ {
switcher->idleData.usePreviousScene = (name == previous_scene_name); switcher->idleData.usePreviousScene =
(name ==
obs_module_text("AdvSceneSwitcher.selectPreviousScene"));
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);
@@ -280,10 +284,13 @@ void AdvSceneSwitcher::setupIdleTab()
} }
ui->idleCheckBox->setChecked(switcher->idleData.idleEnable); ui->idleCheckBox->setChecked(switcher->idleData.idleEnable);
ui->idleScenes->setCurrentText( if (switcher->idleData.usePreviousScene) {
switcher->idleData.usePreviousScene ui->idleScenes->setCurrentText(obs_module_text(
? previous_scene_name "AdvSceneSwitcher.selectPreviousScene"));
: GetWeakSourceName(switcher->idleData.scene).c_str()); } else {
ui->idleScenes->setCurrentText(
GetWeakSourceName(switcher->idleData.scene).c_str());
}
ui->idleTransitions->setCurrentText( ui->idleTransitions->setCurrentText(
GetWeakSourceName(switcher->idleData.transition).c_str()); GetWeakSourceName(switcher->idleData.transition).c_str());
ui->idleSpinBox->setValue(switcher->idleData.time); ui->idleSpinBox->setValue(switcher->idleData.time);

View File

@@ -1,6 +1,7 @@
#include "headers/advanced-scene-switcher.hpp" #include "headers/advanced-scene-switcher.hpp"
#include "headers/utility.hpp" #include "headers/utility.hpp"
bool MediaSwitch::pause = false;
static QMetaObject::Connection addPulse; static QMetaObject::Connection addPulse;
constexpr auto media_played_to_end_idx = 8; constexpr auto media_played_to_end_idx = 8;
@@ -8,18 +9,12 @@ constexpr auto media_any_idx = 9;
void AdvSceneSwitcher::on_mediaAdd_clicked() void AdvSceneSwitcher::on_mediaAdd_clicked()
{ {
ui->mediaAdd->disconnect(addPulse);
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->mediaSwitches.emplace_back(); switcher->mediaSwitches.emplace_back();
QListWidgetItem *item; listAddClicked(ui->mediaSwitches,
item = new QListWidgetItem(ui->mediaSwitches); new MediaSwitchWidget(&switcher->mediaSwitches.back()),
ui->mediaSwitches->addItem(item); ui->mediaAdd, &addPulse);
MediaSwitchWidget *sw =
new MediaSwitchWidget(&switcher->mediaSwitches.back());
item->setSizeHint(sw->minimumSizeHint());
ui->mediaSwitches->setItemWidget(item, sw);
} }
void AdvSceneSwitcher::on_mediaRemove_clicked() void AdvSceneSwitcher::on_mediaRemove_clicked()
@@ -82,6 +77,9 @@ void AdvSceneSwitcher::on_mediaDown_clicked()
void SwitcherData::checkMediaSwitch(bool &match, OBSWeakSource &scene, void SwitcherData::checkMediaSwitch(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition) OBSWeakSource &transition)
{ {
if (MediaSwitch::pause)
return;
for (MediaSwitch &mediaSwitch : mediaSwitches) { for (MediaSwitch &mediaSwitch : mediaSwitches) {
if (!mediaSwitch.initialized()) if (!mediaSwitch.initialized())
continue; continue;
@@ -414,45 +412,52 @@ void swap(MediaSwitch &first, MediaSwitch &second)
void populateMediaStates(QComboBox *list) void populateMediaStates(QComboBox *list)
{ {
list->addItem("None"); list->addItem(obs_module_text("AdvSceneSwitcher.mediaTab.states.none"));
list->addItem("Playing"); list->addItem(
list->addItem("Opening"); obs_module_text("AdvSceneSwitcher.mediaTab.states.playing"));
list->addItem("Buffering"); list->addItem(
list->addItem("Paused"); obs_module_text("AdvSceneSwitcher.mediaTab.states.opening"));
list->addItem("Stopped"); list->addItem(
list->addItem("Ended"); obs_module_text("AdvSceneSwitcher.mediaTab.states.buffering"));
list->addItem("Error"); list->addItem(
list->addItem("Played to end"); obs_module_text("AdvSceneSwitcher.mediaTab.states.paused"));
list->addItem("Any"); list->addItem(
obs_module_text("AdvSceneSwitcher.mediaTab.states.stopped"));
list->addItem(
obs_module_text("AdvSceneSwitcher.mediaTab.states.ended"));
list->addItem(
obs_module_text("AdvSceneSwitcher.mediaTab.states.error"));
list->addItem(obs_module_text(
"AdvSceneSwitcher.mediaTab.states.playedToEnd"));
list->addItem(obs_module_text("AdvSceneSwitcher.mediaTab.states.any"));
} }
void populateTimeRestrictions(QComboBox *list) void populateTimeRestrictions(QComboBox *list)
{ {
list->addItem("None"); list->addItem(obs_module_text(
list->addItem("Time shorter"); "AdvSceneSwitcher.mediaTab.timeRestriction.none"));
list->addItem("Time longer"); list->addItem(obs_module_text(
list->addItem("Time remaining shorter"); "AdvSceneSwitcher.mediaTab.timeRestriction.shorter"));
list->addItem("Time remaining longer"); list->addItem(obs_module_text(
"AdvSceneSwitcher.mediaTab.timeRestriction.longer"));
list->addItem(obs_module_text(
"AdvSceneSwitcher.mediaTab.timeRestriction.remainShorter"));
list->addItem(obs_module_text(
"AdvSceneSwitcher.mediaTab.timeRestriction.remainLonger"));
} }
MediaSwitchWidget::MediaSwitchWidget(MediaSwitch *s) : SwitchWidget(s) MediaSwitchWidget::MediaSwitchWidget(MediaSwitch *s) : SwitchWidget(s)
{ {
meidaSources = new QComboBox(); mediaSources = new QComboBox();
states = new QComboBox(); states = new QComboBox();
timeRestrictions = new QComboBox(); timeRestrictions = new QComboBox();
time = new QSpinBox(); time = new QSpinBox();
whenLabel = new QLabel("When");
stateLabel = new QLabel("state is");
andLabel = new QLabel("and");
switchLabel = new QLabel("switch to");
usingLabel = new QLabel("using");
time->setSuffix("ms"); time->setSuffix("ms");
time->setMaximum(99999999); time->setMaximum(99999999);
time->setMinimum(0); time->setMinimum(0);
QWidget::connect(meidaSources, QWidget::connect(mediaSources,
SIGNAL(currentTextChanged(const QString &)), this, SIGNAL(currentTextChanged(const QString &)), this,
SLOT(SourceChanged(const QString &))); SLOT(SourceChanged(const QString &)));
QWidget::connect(states, SIGNAL(currentIndexChanged(int)), this, QWidget::connect(states, SIGNAL(currentIndexChanged(int)), this,
@@ -462,12 +467,12 @@ MediaSwitchWidget::MediaSwitchWidget(MediaSwitch *s) : SwitchWidget(s)
QWidget::connect(time, SIGNAL(valueChanged(int)), this, QWidget::connect(time, SIGNAL(valueChanged(int)), this,
SLOT(TimeChanged(int))); SLOT(TimeChanged(int)));
AdvSceneSwitcher::populateMediaSelection(meidaSources); AdvSceneSwitcher::populateMediaSelection(mediaSources);
populateMediaStates(states); populateMediaStates(states);
populateTimeRestrictions(timeRestrictions); populateTimeRestrictions(timeRestrictions);
if (s) { if (s) {
meidaSources->setCurrentText( mediaSources->setCurrentText(
GetWeakSourceName(s->source).c_str()); GetWeakSourceName(s->source).c_str());
states->setCurrentIndex(s->state); states->setCurrentIndex(s->state);
timeRestrictions->setCurrentIndex(s->restriction); timeRestrictions->setCurrentIndex(s->restriction);
@@ -476,23 +481,16 @@ MediaSwitchWidget::MediaSwitchWidget(MediaSwitch *s) : SwitchWidget(s)
time->setDisabled(true); time->setDisabled(true);
} }
setStyleSheet("* { background-color: transparent; }");
QHBoxLayout *mainLayout = new QHBoxLayout; QHBoxLayout *mainLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
mainLayout->addWidget(whenLabel); {"{{mediaSources}}", mediaSources},
mainLayout->addWidget(meidaSources); {"{{states}}", states},
mainLayout->addWidget(stateLabel); {"{{timeRestrictions}}", timeRestrictions},
mainLayout->addWidget(states); {"{{time}}", time},
mainLayout->addWidget(andLabel); {"{{scenes}}", scenes},
mainLayout->addWidget(timeRestrictions); {"{{transitions}}", transitions}};
mainLayout->addWidget(time); placeWidgets(obs_module_text("AdvSceneSwitcher.mediaTab.entry"),
mainLayout->addWidget(switchLabel); mainLayout, widgetPlaceholders);
mainLayout->addWidget(scenes);
mainLayout->addWidget(usingLabel);
mainLayout->addWidget(transitions);
mainLayout->addStretch();
setLayout(mainLayout); setLayout(mainLayout);
switchData = s; switchData = s;

View File

@@ -3,264 +3,265 @@
#include "headers/advanced-scene-switcher.hpp" #include "headers/advanced-scene-switcher.hpp"
#include "headers/utility.hpp" #include "headers/utility.hpp"
void AdvSceneSwitcher::on_pauseScenesAdd_clicked() static QMetaObject::Connection addPulse;
void AdvSceneSwitcher::on_pauseAdd_clicked()
{ {
QString sceneName = ui->pauseScenesScenes->currentText(); std::lock_guard<std::mutex> lock(switcher->m);
switcher->pauseEntries.emplace_back();
if (sceneName.isEmpty()) listAddClicked(ui->pauseEntries,
return; new PauseEntryWidget(&switcher->pauseEntries.back()),
ui->pauseAdd, &addPulse);
OBSWeakSource source = GetWeakSourceByQString(sceneName);
QVariant v = QVariant::fromValue(sceneName);
QList<QListWidgetItem *> items =
ui->pauseScenes->findItems(sceneName, Qt::MatchExactly);
if (items.size() == 0) {
QListWidgetItem *item =
new QListWidgetItem(sceneName, ui->pauseScenes);
item->setData(Qt::UserRole, v);
std::lock_guard<std::mutex> lock(switcher->m);
switcher->pauseScenesSwitches.emplace_back(source);
ui->pauseScenes->sortItems();
}
} }
void AdvSceneSwitcher::on_pauseScenesRemove_clicked() void AdvSceneSwitcher::on_pauseRemove_clicked()
{ {
QListWidgetItem *item = ui->pauseScenes->currentItem(); QListWidgetItem *item = ui->pauseEntries->currentItem();
if (!item) if (!item)
return; return;
QString pauseScene = item->data(Qt::UserRole).toString();
{ {
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
auto &switches = switcher->pauseScenesSwitches; int idx = ui->pauseEntries->currentRow();
auto &switches = switcher->pauseEntries;
for (auto it = switches.begin(); it != switches.end(); ++it) { switches.erase(switches.begin() + idx);
auto &s = *it;
if (s == GetWeakSourceByQString(pauseScene)) {
switches.erase(it);
break;
}
}
} }
delete item; delete item;
} }
void AdvSceneSwitcher::on_pauseWindowsAdd_clicked() void AdvSceneSwitcher::on_pauseUp_clicked()
{ {
QString windowName = ui->pauseWindowsWindows->currentText(); int index = ui->pauseEntries->currentRow();
if (!listMoveUp(ui->pauseEntries))
if (windowName.isEmpty())
return; return;
QVariant v = QVariant::fromValue(windowName); PauseEntryWidget *s1 = (PauseEntryWidget *)ui->pauseEntries->itemWidget(
ui->pauseEntries->item(index));
QList<QListWidgetItem *> items = PauseEntryWidget *s2 = (PauseEntryWidget *)ui->pauseEntries->itemWidget(
ui->pauseWindows->findItems(windowName, Qt::MatchExactly); ui->pauseEntries->item(index - 1));
PauseEntryWidget::swapSwitchData(s1, s2);
if (items.size() == 0) {
QListWidgetItem *item =
new QListWidgetItem(windowName, ui->pauseWindows);
item->setData(Qt::UserRole, v);
std::lock_guard<std::mutex> lock(switcher->m);
switcher->pauseWindowsSwitches.emplace_back(
windowName.toUtf8().constData());
ui->pauseWindows->sortItems();
}
}
void AdvSceneSwitcher::on_pauseWindowsRemove_clicked()
{
QListWidgetItem *item = ui->pauseWindows->currentItem();
if (!item)
return;
QString windowName = item->data(Qt::UserRole).toString();
{
std::lock_guard<std::mutex> lock(switcher->m);
auto &switches = switcher->pauseWindowsSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it) {
auto &s = *it;
if (s == windowName.toUtf8().constData()) {
switches.erase(it);
break;
}
}
}
delete item;
}
void AdvSceneSwitcher::on_pauseScenes_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem *item = ui->pauseScenes->item(idx);
QString scene = item->data(Qt::UserRole).toString();
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->pauseScenesSwitches) {
std::string name = GetWeakSourceName(s); std::swap(switcher->pauseEntries[index],
if (scene.compare(name.c_str()) == 0) { switcher->pauseEntries[index - 1]);
ui->pauseScenesScenes->setCurrentText(name.c_str());
break;
}
}
} }
void AdvSceneSwitcher::on_pauseWindows_currentRowChanged(int idx) void AdvSceneSwitcher::on_pauseDown_clicked()
{ {
if (loading) int index = ui->pauseEntries->currentRow();
return;
if (idx == -1) if (!listMoveDown(ui->pauseEntries))
return; return;
QListWidgetItem *item = ui->pauseWindows->item(idx); PauseEntryWidget *s1 = (PauseEntryWidget *)ui->pauseEntries->itemWidget(
ui->pauseEntries->item(index));
QString window = item->data(Qt::UserRole).toString(); PauseEntryWidget *s2 = (PauseEntryWidget *)ui->pauseEntries->itemWidget(
ui->pauseEntries->item(index + 1));
PauseEntryWidget::swapSwitchData(s1, s2);
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->pauseWindowsSwitches) {
if (window.compare(s.c_str()) == 0) { std::swap(switcher->pauseEntries[index],
ui->pauseWindowsWindows->setCurrentText(s.c_str()); switcher->pauseEntries[index + 1]);
break; }
}
void resetPause()
{
DefaultSceneTransition::pause = false;
WindowSwitch::pause = false;
ExecutableSwitch::pause = false;
ScreenRegionSwitch::pause = false;
MediaSwitch::pause = false;
FileSwitch::pause = false;
RandomSwitch::pause = false;
TimeSwitch::pause = false;
IdleData::pause = false;
SceneSequenceSwitch::pause = false;
AudioSwitch::pause = false;
}
void setPauseTarget(PauseTarget &target, bool &verbose)
{
switch (target) {
case PauseTarget::All:
if (verbose)
blog(LOG_INFO, "pause all switching");
break;
case PauseTarget::Transition:
if (verbose)
blog(LOG_INFO, "pause def_transition switching");
DefaultSceneTransition::pause = true;
break;
case PauseTarget::Window:
if (verbose)
blog(LOG_INFO, "pause window switching");
WindowSwitch::pause = true;
break;
case PauseTarget::Executable:
if (verbose)
blog(LOG_INFO, "pause exec switching");
ExecutableSwitch::pause = true;
break;
case PauseTarget::Region:
if (verbose)
blog(LOG_INFO, "pause region switching");
ScreenRegionSwitch::pause = true;
break;
case PauseTarget::Media:
if (verbose)
blog(LOG_INFO, "pause media switching");
MediaSwitch::pause = true;
break;
case PauseTarget::File:
if (verbose)
blog(LOG_INFO, "pause file switching");
FileSwitch::pause = true;
break;
case PauseTarget::Random:
if (verbose)
blog(LOG_INFO, "pause random switching");
RandomSwitch::pause = true;
break;
case PauseTarget::Time:
if (verbose)
blog(LOG_INFO, "pause time switching");
TimeSwitch::pause = true;
break;
case PauseTarget::Idle:
if (verbose)
blog(LOG_INFO, "pause idle switching");
IdleData::pause = true;
break;
case PauseTarget::Sequence:
if (verbose)
blog(LOG_INFO, "pause sequence switching");
SceneSequenceSwitch::pause = true;
break;
case PauseTarget::Audio:
if (verbose)
blog(LOG_INFO, "pause audio switching");
AudioSwitch::pause = true;
break;
} }
} }
int AdvSceneSwitcher::PauseScenesFindByData(const QString &scene) bool checkPauseScene(obs_weak_source_t *currentScene, obs_weak_source_t *scene,
PauseTarget &target, bool &verbose)
{ {
int count = ui->pauseScenes->count(); if (currentScene != scene)
int idx = -1; return false;
for (int i = 0; i < count; i++) { setPauseTarget(target, verbose);
QListWidgetItem *item = ui->pauseScenes->item(i); if (target == PauseTarget::All)
QString itemRegion = item->data(Qt::UserRole).toString(); return true;
return false;
if (itemRegion == scene) {
idx = i;
break;
}
}
return idx;
} }
bool checkPauseWindow(std::string &currentTitle, std::string &title,
int AdvSceneSwitcher::PauseWindowsFindByData(const QString &window) PauseTarget &target, bool &verbose)
{ {
int count = ui->pauseWindows->count(); if (currentTitle != title)
int idx = -1; return false;
for (int i = 0; i < count; i++) { setPauseTarget(target, verbose);
QListWidgetItem *item = ui->pauseWindows->item(i); if (target == PauseTarget::All)
QString itemRegion = item->data(Qt::UserRole).toString(); return true;
return false;
if (itemRegion == window) {
idx = i;
break;
}
}
return idx;
} }
bool SwitcherData::checkPause() bool SwitcherData::checkPause()
{ {
bool pause = false; bool pauseAll = false;
std::string title;
GetCurrentWindowTitle(title);
resetPause();
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);
for (OBSWeakSource &s : pauseScenesSwitches) { for (PauseEntry &s : pauseEntries) {
if (s == ws) { if (s.pauseType == PauseType::Scene)
pause = true; pauseAll = checkPauseScene(ws, s.scene, s.pauseTarget,
verbose);
else
pauseAll = checkPauseWindow(title, s.window,
s.pauseTarget, verbose);
if (pauseAll)
break; break;
}
} }
obs_source_release(currentSource); obs_source_release(currentSource);
obs_weak_source_release(ws); obs_weak_source_release(ws);
std::string title; return pauseAll;
if (!pause) {
//lock.unlock();
GetCurrentWindowTitle(title);
//lock.lock();
for (std::string &window : pauseWindowsSwitches) {
if (window == title) {
pause = true;
break;
}
}
}
if (!pause) {
//lock.unlock();
GetCurrentWindowTitle(title);
//lock.lock();
for (std::string &window : pauseWindowsSwitches) {
try {
bool matches = std::regex_match(
title, std::regex(window));
if (matches) {
pause = true;
break;
}
} catch (const std::regex_error &) {
}
}
}
if (verbose && pause)
blog(LOG_INFO, "pause match");
return pause;
} }
void SwitcherData::savePauseSwitches(obs_data_t *obj) void SwitcherData::savePauseSwitches(obs_data_t *obj)
{ {
obs_data_array_t *pauseScenesArray = obs_data_array_create(); obs_data_array_t *pauseScenesArray = obs_data_array_create();
for (OBSWeakSource &scene : switcher->pauseScenesSwitches) { for (PauseEntry &s : switcher->pauseEntries) {
obs_data_t *array_obj = obs_data_create(); obs_data_t *array_obj = obs_data_create();
obs_source_t *source = obs_weak_source_get_source(scene); obs_data_set_int(array_obj, "pauseType",
static_cast<int>(s.pauseType));
obs_data_set_int(array_obj, "pauseTarget",
static_cast<int>(s.pauseTarget));
obs_data_set_string(array_obj, "pauseWindow", s.window.c_str());
obs_source_t *source = obs_weak_source_get_source(s.scene);
if (source) { if (source) {
const char *n = obs_source_get_name(source); const char *n = obs_source_get_name(source);
obs_data_set_string(array_obj, "pauseScene", n); obs_data_set_string(array_obj, "pauseScene", n);
obs_data_array_push_back(pauseScenesArray, array_obj);
} }
obs_data_array_push_back(pauseScenesArray, array_obj);
obs_source_release(source); obs_source_release(source);
obs_data_release(array_obj); obs_data_release(array_obj);
} }
obs_data_set_array(obj, "pauseScenes", pauseScenesArray); obs_data_set_array(obj, "pauseEntries", pauseScenesArray);
obs_data_set_int(obj, "oldPauseValuesImported", 1);
obs_data_array_release(pauseScenesArray); obs_data_array_release(pauseScenesArray);
obs_data_array_t *pauseWindowsArray = obs_data_array_create();
for (std::string &window : switcher->pauseWindowsSwitches) {
obs_data_t *array_obj = obs_data_create();
obs_data_set_string(array_obj, "pauseWindow", window.c_str());
obs_data_array_push_back(pauseWindowsArray, array_obj);
obs_data_release(array_obj);
}
obs_data_set_array(obj, "pauseWindows", pauseWindowsArray);
obs_data_array_release(pauseWindowsArray);
} }
void SwitcherData::loadPauseSwitches(obs_data_t *obj) void SwitcherData::loadPauseSwitches(obs_data_t *obj)
{ {
switcher->pauseScenesSwitches.clear(); switcher->pauseEntries.clear();
// To be removed in future builds once most users have migrated
loadOldPauseSwitches(obj);
obs_data_array_t *pauseArray = obs_data_get_array(obj, "pauseEntries");
size_t count = obs_data_array_count(pauseArray);
for (size_t i = 0; i < count; i++) {
obs_data_t *array_obj = obs_data_array_item(pauseArray, i);
PauseType type = static_cast<PauseType>(
obs_data_get_int(array_obj, "pauseType"));
PauseTarget target = static_cast<PauseTarget>(
obs_data_get_int(array_obj, "pauseTarget"));
const char *scene =
obs_data_get_string(array_obj, "pauseScene");
const char *window =
obs_data_get_string(array_obj, "pauseWindow");
switcher->pauseEntries.emplace_back(GetWeakSourceByName(scene),
type, target, window);
obs_data_release(array_obj);
}
obs_data_array_release(pauseArray);
}
void SwitcherData::loadOldPauseSwitches(obs_data_t *obj)
{
if (obs_data_get_int(obj, "oldPauseValuesImported"))
return;
obs_data_array_t *pauseScenesArray = obs_data_array_t *pauseScenesArray =
obs_data_get_array(obj, "pauseScenes"); obs_data_get_array(obj, "pauseScenes");
@@ -273,15 +274,14 @@ void SwitcherData::loadPauseSwitches(obs_data_t *obj)
const char *scene = const char *scene =
obs_data_get_string(array_obj, "pauseScene"); obs_data_get_string(array_obj, "pauseScene");
switcher->pauseScenesSwitches.emplace_back( switcher->pauseEntries.emplace_back(GetWeakSourceByName(scene),
GetWeakSourceByName(scene)); PauseType::Scene,
PauseTarget::All, "");
obs_data_release(array_obj); obs_data_release(array_obj);
} }
obs_data_array_release(pauseScenesArray); obs_data_array_release(pauseScenesArray);
switcher->pauseWindowsSwitches.clear();
obs_data_array_t *pauseWindowsArray = obs_data_array_t *pauseWindowsArray =
obs_data_get_array(obj, "pauseWindows"); obs_data_get_array(obj, "pauseWindows");
count = obs_data_array_count(pauseWindowsArray); count = obs_data_array_count(pauseWindowsArray);
@@ -293,7 +293,8 @@ void SwitcherData::loadPauseSwitches(obs_data_t *obj)
const char *window = const char *window =
obs_data_get_string(array_obj, "pauseWindow"); obs_data_get_string(array_obj, "pauseWindow");
switcher->pauseWindowsSwitches.emplace_back(window); switcher->pauseEntries.emplace_back(nullptr, PauseType::Window,
PauseTarget::All, window);
obs_data_release(array_obj); obs_data_release(array_obj);
} }
@@ -302,23 +303,153 @@ void SwitcherData::loadPauseSwitches(obs_data_t *obj)
void AdvSceneSwitcher::setupPauseTab() void AdvSceneSwitcher::setupPauseTab()
{ {
populateSceneSelection(ui->pauseScenesScenes, false); for (auto &s : switcher->pauseEntries) {
populateWindowSelection(ui->pauseWindowsWindows); QListWidgetItem *item;
item = new QListWidgetItem(ui->pauseEntries);
for (auto &scene : switcher->pauseScenesSwitches) { ui->pauseEntries->addItem(item);
std::string sceneName = GetWeakSourceName(scene); PauseEntryWidget *sw = new PauseEntryWidget(&s);
QString text = QString::fromStdString(sceneName); item->setSizeHint(sw->minimumSizeHint());
ui->pauseEntries->setItemWidget(item, sw);
QListWidgetItem *item =
new QListWidgetItem(text, ui->pauseScenes);
item->setData(Qt::UserRole, text);
} }
for (auto &window : switcher->pauseWindowsSwitches) { if (switcher->pauseEntries.size() == 0)
QString text = QString::fromStdString(window); addPulse = PulseWidget(ui->pauseAdd, QColor(Qt::green));
}
QListWidgetItem *item = void populatePauseTypes(QComboBox *list)
new QListWidgetItem(text, ui->pauseWindows); {
item->setData(Qt::UserRole, text); list->addItem(
obs_module_text("AdvSceneSwitcher.pauseTab.pauseTypeScene"));
list->addItem(
obs_module_text("AdvSceneSwitcher.pauseTab.pauseTypeWindow"));
}
void populatePauseTargets(QComboBox *list)
{
list->addItem(
obs_module_text("AdvSceneSwitcher.pauseTab.pauseTargetAll"));
list->addItem(obs_module_text("AdvSceneSwitcher.transitionTab.title"));
list->addItem(obs_module_text("AdvSceneSwitcher.windowTitleTab.title"));
list->addItem(obs_module_text("AdvSceneSwitcher.executableTab.title"));
list->addItem(
obs_module_text("AdvSceneSwitcher.screenRegionTab.title"));
list->addItem(obs_module_text("AdvSceneSwitcher.mediaTab.title"));
list->addItem(obs_module_text("AdvSceneSwitcher.fileTab.title"));
list->addItem(obs_module_text("AdvSceneSwitcher.randomTab.title"));
list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.title"));
list->addItem(obs_module_text("AdvSceneSwitcher.idleTab.title"));
list->addItem(
obs_module_text("AdvSceneSwitcher.sceneSequenceTab.title"));
list->addItem(obs_module_text("AdvSceneSwitcher.audioTab.title"));
}
PauseEntryWidget::PauseEntryWidget(PauseEntry *s) : SwitchWidget(s, false)
{
pauseTypes = new QComboBox();
pauseTargets = new QComboBox();
windows = new QComboBox();
QWidget::connect(pauseTypes, SIGNAL(currentIndexChanged(int)), this,
SLOT(PauseTypeChanged(int)));
QWidget::connect(pauseTargets, SIGNAL(currentIndexChanged(int)), this,
SLOT(PauseTargetChanged(int)));
QWidget::connect(windows, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(WindowChanged(const QString &)));
populatePauseTypes(pauseTypes);
populatePauseTargets(pauseTargets);
AdvSceneSwitcher::populateWindowSelection(windows);
windows->setEditable(true);
windows->setMaxVisibleItems(20);
if (s) {
scenes->setCurrentText(GetWeakSourceName(s->scene).c_str());
pauseTypes->setCurrentIndex(static_cast<int>(s->pauseType));
pauseTargets->setCurrentIndex(static_cast<int>(s->pauseTarget));
windows->setCurrentText(s->window.c_str());
if (s->pauseType == PauseType::Scene) {
windows->setDisabled(true);
windows->setVisible(false);
} else {
scenes->setDisabled(true);
scenes->setVisible(false);
}
}
QHBoxLayout *mainLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{scenes}}", scenes},
{"{{pauseTypes}}", pauseTypes},
{"{{pauseTargets}}", pauseTargets},
{"{{windows}}", windows}};
placeWidgets(obs_module_text("AdvSceneSwitcher.pauseTab.pauseEntry"),
mainLayout, widgetPlaceholders);
setLayout(mainLayout);
switchData = s;
loading = false;
}
PauseEntry *PauseEntryWidget::getSwitchData()
{
return switchData;
}
void PauseEntryWidget::setSwitchData(PauseEntry *s)
{
switchData = s;
}
void PauseEntryWidget::swapSwitchData(PauseEntryWidget *s1,
PauseEntryWidget *s2)
{
SwitchWidget::swapSwitchData(s1, s2);
PauseEntry *t = s1->getSwitchData();
s1->setSwitchData(s2->getSwitchData());
s2->setSwitchData(t);
}
void PauseEntryWidget::PauseTypeChanged(int index)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->pauseType = static_cast<PauseType>(index);
if (switchData->pauseType == PauseType::Scene) {
windows->setDisabled(true);
windows->setVisible(false);
scenes->setDisabled(false);
scenes->setVisible(true);
} else {
scenes->setDisabled(true);
scenes->setVisible(false);
windows->setDisabled(false);
windows->setVisible(true);
} }
} }
void PauseEntryWidget::PauseTargetChanged(int index)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->pauseTarget = static_cast<PauseTarget>(index);
}
void PauseEntryWidget::WindowChanged(const QString &text)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->window = text.toStdString();
}
bool PauseEntry::valid()
{
return true;
}

View File

@@ -3,22 +3,17 @@
#include "headers/advanced-scene-switcher.hpp" #include "headers/advanced-scene-switcher.hpp"
#include "headers/utility.hpp" #include "headers/utility.hpp"
bool RandomSwitch::pause = false;
static QMetaObject::Connection addPulse; static QMetaObject::Connection addPulse;
void AdvSceneSwitcher::on_randomAdd_clicked() void AdvSceneSwitcher::on_randomAdd_clicked()
{ {
ui->randomAdd->disconnect(addPulse);
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->randomSwitches.emplace_back(); switcher->randomSwitches.emplace_back();
QListWidgetItem *item; listAddClicked(ui->randomSwitches,
item = new QListWidgetItem(ui->randomSwitches); new RandomSwitchWidget(&switcher->randomSwitches.back()),
ui->randomSwitches->addItem(item); ui->randomAdd, &addPulse);
RandomSwitchWidget *sw =
new RandomSwitchWidget(&switcher->randomSwitches.back());
item->setSizeHint(sw->minimumSizeHint());
ui->randomSwitches->setItemWidget(item, sw);
} }
void AdvSceneSwitcher::on_randomRemove_clicked() void AdvSceneSwitcher::on_randomRemove_clicked()
@@ -40,7 +35,7 @@ void AdvSceneSwitcher::on_randomRemove_clicked()
void SwitcherData::checkRandom(bool &match, OBSWeakSource &scene, void SwitcherData::checkRandom(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition, int &delay) OBSWeakSource &transition, int &delay)
{ {
if (randomSwitches.size() == 0) if (randomSwitches.size() == 0 || RandomSwitch::pause)
return; return;
std::deque<RandomSwitch> rs(randomSwitches); std::deque<RandomSwitch> rs(randomSwitches);
@@ -143,10 +138,6 @@ RandomSwitchWidget::RandomSwitchWidget(RandomSwitch *s) : SwitchWidget(s, false)
{ {
delay = new QDoubleSpinBox(); delay = new QDoubleSpinBox();
switchLabel = new QLabel("If no switch condition is met switch to ");
usingLabel = new QLabel("using");
forLabel = new QLabel("for");
QWidget::connect(delay, SIGNAL(valueChanged(double)), this, QWidget::connect(delay, SIGNAL(valueChanged(double)), this,
SLOT(DelayChanged(double))); SLOT(DelayChanged(double)));
@@ -157,18 +148,13 @@ RandomSwitchWidget::RandomSwitchWidget(RandomSwitch *s) : SwitchWidget(s, false)
delay->setValue(s->delay); delay->setValue(s->delay);
} }
setStyleSheet("* { background-color: transparent; }");
QHBoxLayout *mainLayout = new QHBoxLayout; QHBoxLayout *mainLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
mainLayout->addWidget(switchLabel); {"{{scenes}}", scenes},
mainLayout->addWidget(scenes); {"{{transitions}}", transitions},
mainLayout->addWidget(usingLabel); {"{{delay}}", delay}};
mainLayout->addWidget(transitions); placeWidgets(obs_module_text("AdvSceneSwitcher.randomTab.entry"),
mainLayout->addWidget(forLabel); mainLayout, widgetPlaceholders);
mainLayout->addWidget(delay);
mainLayout->addStretch();
setLayout(mainLayout); setLayout(mainLayout);
switchData = s; switchData = s;

View File

@@ -3,6 +3,7 @@
#include "headers/advanced-scene-switcher.hpp" #include "headers/advanced-scene-switcher.hpp"
#include "headers/utility.hpp" #include "headers/utility.hpp"
bool ScreenRegionSwitch::pause = false;
static QMetaObject::Connection addPulse; static QMetaObject::Connection addPulse;
void AdvSceneSwitcher::clearFrames(QListWidget *list) void AdvSceneSwitcher::clearFrames(QListWidget *list)
@@ -27,12 +28,14 @@ void showCurrentFrame(QListWidget *list)
void AdvSceneSwitcher::SetShowFrames() void AdvSceneSwitcher::SetShowFrames()
{ {
ui->showFrame->setText("Show guide frames"); ui->showFrame->setText(obs_module_text(
"AdvSceneSwitcher.screenRegionTab.showGuideFrames"));
} }
void AdvSceneSwitcher::SetHideFrames() void AdvSceneSwitcher::SetHideFrames()
{ {
ui->showFrame->setText("Hide guide frames"); ui->showFrame->setText(obs_module_text(
"AdvSceneSwitcher.screenRegionTab.hideGuideFrames"));
} }
void AdvSceneSwitcher::on_showFrame_clicked() void AdvSceneSwitcher::on_showFrame_clicked()
@@ -61,18 +64,13 @@ void AdvSceneSwitcher::on_screenRegionSwitches_currentRowChanged(int idx)
void AdvSceneSwitcher::on_screenRegionAdd_clicked() void AdvSceneSwitcher::on_screenRegionAdd_clicked()
{ {
ui->screenRegionAdd->disconnect(addPulse);
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->screenRegionSwitches.emplace_back(); switcher->screenRegionSwitches.emplace_back();
QListWidgetItem *item; listAddClicked(
item = new QListWidgetItem(ui->screenRegionSwitches); ui->screenRegionSwitches,
ui->screenRegionSwitches->addItem(item); new ScreenRegionWidget(&switcher->screenRegionSwitches.back()),
ScreenRegionWidget *sw = ui->screenRegionAdd, &addPulse);
new ScreenRegionWidget(&switcher->screenRegionSwitches.back());
item->setSizeHint(sw->minimumSizeHint());
ui->screenRegionSwitches->setItemWidget(item, sw);
} }
void AdvSceneSwitcher::on_screenRegionRemove_clicked() void AdvSceneSwitcher::on_screenRegionRemove_clicked()
@@ -135,6 +133,9 @@ void AdvSceneSwitcher::on_screenRegionDown_clicked()
void SwitcherData::checkScreenRegionSwitch(bool &match, OBSWeakSource &scene, void SwitcherData::checkScreenRegionSwitch(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition) OBSWeakSource &transition)
{ {
if (ScreenRegionSwitch::pause)
return;
std::pair<int, int> cursorPos = getCursorPos(); std::pair<int, int> cursorPos = getCursorPos();
int minRegionSize = 99999; int minRegionSize = 99999;
@@ -257,11 +258,6 @@ ScreenRegionWidget::ScreenRegionWidget(ScreenRegionSwitch *s)
maxX = new QSpinBox(); maxX = new QSpinBox();
maxY = new QSpinBox(); maxY = new QSpinBox();
cursorLabel = new QLabel("If cursor is in");
xLabel = new QLabel("x");
switchLabel = new QLabel("switch to");
usingLabel = new QLabel("using");
minX->setPrefix("Min X: "); minX->setPrefix("Min X: ");
minY->setPrefix("Min Y: "); minY->setPrefix("Min Y: ");
maxX->setPrefix("Max X: "); maxX->setPrefix("Max X: ");
@@ -293,22 +289,13 @@ ScreenRegionWidget::ScreenRegionWidget(ScreenRegionSwitch *s)
maxY->setValue(s->maxY); maxY->setValue(s->maxY);
} }
setStyleSheet("* { background-color: transparent; }");
QHBoxLayout *mainLayout = new QHBoxLayout; QHBoxLayout *mainLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
mainLayout->addWidget(cursorLabel); {"{{minX}}", minX}, {"{{minY}}", minY},
mainLayout->addWidget(minX); {"{{maxX}}", maxX}, {"{{maxY}}", maxY},
mainLayout->addWidget(minY); {"{{scenes}}", scenes}, {"{{transitions}}", transitions}};
mainLayout->addWidget(xLabel); placeWidgets(obs_module_text("AdvSceneSwitcher.screenRegionTab.entry"),
mainLayout->addWidget(maxX); mainLayout, widgetPlaceholders);
mainLayout->addWidget(maxY);
mainLayout->addWidget(switchLabel);
mainLayout->addWidget(scenes);
mainLayout->addWidget(usingLabel);
mainLayout->addWidget(transitions);
mainLayout->addStretch();
setLayout(mainLayout); setLayout(mainLayout);
switchData = s; switchData = s;

View File

@@ -5,22 +5,18 @@
#include "headers/advanced-scene-switcher.hpp" #include "headers/advanced-scene-switcher.hpp"
#include "headers/utility.hpp" #include "headers/utility.hpp"
bool SceneSequenceSwitch::pause = false;
static QMetaObject::Connection addPulse; static QMetaObject::Connection addPulse;
void AdvSceneSwitcher::on_sceneSequenceAdd_clicked() void AdvSceneSwitcher::on_sceneSequenceAdd_clicked()
{ {
ui->sceneSequenceAdd->disconnect(addPulse);
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->sceneSequenceSwitches.emplace_back(); switcher->sceneSequenceSwitches.emplace_back();
QListWidgetItem *item; listAddClicked(
item = new QListWidgetItem(ui->sceneSequenceSwitches); ui->sceneSequenceSwitches,
ui->sceneSequenceSwitches->addItem(item); new SequenceWidget(&switcher->sceneSequenceSwitches.back()),
SequenceWidget *sw = ui->sceneSequenceAdd, &addPulse);
new SequenceWidget(&switcher->sceneSequenceSwitches.back());
item->setSizeHint(sw->minimumSizeHint());
ui->sceneSequenceSwitches->setItemWidget(item, sw);
} }
void AdvSceneSwitcher::on_sceneSequenceRemove_clicked() void AdvSceneSwitcher::on_sceneSequenceRemove_clicked()
@@ -92,8 +88,12 @@ void AdvSceneSwitcher::on_sceneSequenceDown_clicked()
void AdvSceneSwitcher::on_sceneSequenceSave_clicked() void AdvSceneSwitcher::on_sceneSequenceSave_clicked()
{ {
QString directory = QFileDialog::getSaveFileName( QString directory = QFileDialog::getSaveFileName(
this, tr("Save Scene Sequence to file ..."), this,
QDir::currentPath(), tr("Text files (*.txt)")); tr(obs_module_text(
"AdvSceneSwitcher.sceneSequenceTab.saveTitle")),
QDir::currentPath(),
tr(obs_module_text(
"AdvSceneSwitcher.sceneSequenceTab.fileType")));
if (directory.isEmpty()) if (directory.isEmpty())
return; return;
QFile file(directory); QFile file(directory);
@@ -109,8 +109,12 @@ void AdvSceneSwitcher::on_sceneSequenceSave_clicked()
void AdvSceneSwitcher::on_sceneSequenceLoad_clicked() void AdvSceneSwitcher::on_sceneSequenceLoad_clicked()
{ {
QString directory = QFileDialog::getOpenFileName( QString directory = QFileDialog::getOpenFileName(
this, tr("Select a file to read Scene Sequence from ..."), this,
QDir::currentPath(), tr("Text files (*.txt)")); tr(obs_module_text(
"AdvSceneSwitcher.sceneSequenceTab.loadTitle")),
QDir::currentPath(),
tr(obs_module_text(
"AdvSceneSwitcher.sceneSequenceTab.fileType")));
if (directory.isEmpty()) if (directory.isEmpty())
return; return;
@@ -123,8 +127,8 @@ void AdvSceneSwitcher::on_sceneSequenceLoad_clicked()
if (!obj) { if (!obj) {
QMessageBox Msgbox; QMessageBox Msgbox;
Msgbox.setText( Msgbox.setText(obs_module_text(
"Advanced Scene Switcher failed to import settings!"); "AdvSceneSwitcher.sceneSequenceTab.loadFail"));
Msgbox.exec(); Msgbox.exec();
return; return;
} }
@@ -143,8 +147,8 @@ void AdvSceneSwitcher::on_sceneSequenceLoad_clicked()
obs_data_release(obj); obs_data_release(obj);
QMessageBox Msgbox; QMessageBox Msgbox;
Msgbox.setText( Msgbox.setText(obs_module_text(
"Advanced Scene Switcher settings imported successfully!"); "AdvSceneSwitcher.sceneSequenceTab.loadSuccess"));
Msgbox.exec(); Msgbox.exec();
close(); close();
} }
@@ -153,6 +157,9 @@ void SwitcherData::checkSceneSequence(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition, OBSWeakSource &transition,
std::unique_lock<std::mutex> &lock) std::unique_lock<std::mutex> &lock)
{ {
if (SceneSequenceSwitch::pause)
return;
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);
@@ -304,9 +311,9 @@ void SceneSequenceSwitch::logSleep(int dur)
void populateDelayUnits(QComboBox *list) void populateDelayUnits(QComboBox *list)
{ {
list->addItem("seconds"); list->addItem(obs_module_text("AdvSceneSwitcher.unit.secends"));
list->addItem("minutes"); list->addItem(obs_module_text("AdvSceneSwitcher.unit.minutes"));
list->addItem("hours"); list->addItem(obs_module_text("AdvSceneSwitcher.unit.hours"));
} }
SequenceWidget::SequenceWidget(SceneSequenceSwitch *s) : SwitchWidget(s) SequenceWidget::SequenceWidget(SceneSequenceSwitch *s) : SwitchWidget(s)
@@ -315,11 +322,6 @@ SequenceWidget::SequenceWidget(SceneSequenceSwitch *s) : SwitchWidget(s)
delayUnits = new QComboBox(); delayUnits = new QComboBox();
startScenes = new QComboBox(); startScenes = new QComboBox();
whenLabel = new QLabel("When");
switchLabel = new QLabel("is active switch to");
afterLabel = new QLabel("after");
usingLabel = new QLabel("using");
QWidget::connect(delay, SIGNAL(valueChanged(double)), this, QWidget::connect(delay, SIGNAL(valueChanged(double)), this,
SLOT(DelayChanged(double))); SLOT(DelayChanged(double)));
QWidget::connect(delayUnits, SIGNAL(currentIndexChanged(int)), this, QWidget::connect(delayUnits, SIGNAL(currentIndexChanged(int)), this,
@@ -350,21 +352,15 @@ SequenceWidget::SequenceWidget(SceneSequenceSwitch *s) : SwitchWidget(s)
GetWeakSourceName(s->startScene).c_str()); GetWeakSourceName(s->startScene).c_str());
} }
setStyleSheet("* { background-color: transparent; }");
QHBoxLayout *mainLayout = new QHBoxLayout; QHBoxLayout *mainLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
mainLayout->addWidget(whenLabel); {"{{startScenes}}", startScenes},
mainLayout->addWidget(startScenes); {"{{scenes}}", scenes},
mainLayout->addWidget(switchLabel); {"{{delay}}", delay},
mainLayout->addWidget(scenes); {"{{delayUnits}}", delayUnits},
mainLayout->addWidget(afterLabel); {"{{transitions}}", transitions}};
mainLayout->addWidget(delay); placeWidgets(obs_module_text("AdvSceneSwitcher.sceneSequenceTab.entry"),
mainLayout->addWidget(delayUnits); mainLayout, widgetPlaceholders);
mainLayout->addWidget(usingLabel);
mainLayout->addWidget(transitions);
mainLayout->addStretch();
setLayout(mainLayout); setLayout(mainLayout);
switchData = s; switchData = s;

View File

@@ -1,22 +1,17 @@
#include "headers/advanced-scene-switcher.hpp" #include "headers/advanced-scene-switcher.hpp"
#include "headers/utility.hpp" #include "headers/utility.hpp"
bool TimeSwitch::pause = false;
static QMetaObject::Connection addPulse; static QMetaObject::Connection addPulse;
void AdvSceneSwitcher::on_timeAdd_clicked() void AdvSceneSwitcher::on_timeAdd_clicked()
{ {
ui->timeAdd->disconnect(addPulse);
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->timeSwitches.emplace_back(); switcher->timeSwitches.emplace_back();
QListWidgetItem *item; listAddClicked(ui->timeSwitches,
item = new QListWidgetItem(ui->timeSwitches); new TimeSwitchWidget(&switcher->timeSwitches.back()),
ui->timeSwitches->addItem(item); ui->timeAdd, &addPulse);
TimeSwitchWidget *sw =
new TimeSwitchWidget(&switcher->timeSwitches.back());
item->setSizeHint(sw->minimumSizeHint());
ui->timeSwitches->setItemWidget(item, sw);
} }
void AdvSceneSwitcher::on_timeRemove_clicked() void AdvSceneSwitcher::on_timeRemove_clicked()
@@ -74,6 +69,9 @@ void AdvSceneSwitcher::on_timeDown_clicked()
bool timesAreInInterval(QTime &time1, QTime &time2, int &interval) bool timesAreInInterval(QTime &time1, QTime &time2, int &interval)
{ {
if (time1.isNull() || time2.isNull())
return false;
bool ret = false; bool ret = false;
QTime validSwitchTimeWindow = time1.addMSecs(interval); QTime validSwitchTimeWindow = time1.addMSecs(interval);
@@ -110,7 +108,7 @@ bool checkRegularTime(TimeSwitch &s, int &interval)
void SwitcherData::checkTimeSwitch(bool &match, OBSWeakSource &scene, void SwitcherData::checkTimeSwitch(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition) OBSWeakSource &transition)
{ {
if (timeSwitches.size() == 0) if (TimeSwitch::pause)
return; return;
for (TimeSwitch &s : timeSwitches) { for (TimeSwitch &s : timeSwitches) {
@@ -214,19 +212,18 @@ void AdvSceneSwitcher::setupTimeTab()
void populateTriggers(QComboBox *list) void populateTriggers(QComboBox *list)
{ {
list->addItem("On any day"); list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.anyDay"));
list->addItem("Mondays"); list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.mondays"));
list->addItem("Tuesdays"); list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.tuesdays"));
list->addItem("Wednesdays"); list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.wednesdays"));
list->addItem("Thursdays"); list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.thursdays"));
list->addItem("Fridays"); list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.fridays"));
list->addItem("Saturdays"); list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.saturdays"));
list->addItem("Sundays"); list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.sundays"));
list->addItem("Atfer streaming/recording start"); list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.afterstart"));
list->setItemData( list->setItemData(
8, 8, obs_module_text("AdvSceneSwitcher.timeTab.afterstart.tip"),
"The time relative to the start of streaming / recording will be used",
Qt::ToolTipRole); Qt::ToolTipRole);
} }
@@ -235,10 +232,6 @@ TimeSwitchWidget::TimeSwitchWidget(TimeSwitch *s) : SwitchWidget(s)
triggers = new QComboBox(); triggers = new QComboBox();
time = new QTimeEdit(); time = new QTimeEdit();
atLabel = new QLabel("at");
switchLabel = new QLabel("switch to");
usingLabel = new QLabel("using");
QWidget::connect(triggers, SIGNAL(currentIndexChanged(int)), this, QWidget::connect(triggers, SIGNAL(currentIndexChanged(int)), this,
SLOT(TriggerChanged(int))); SLOT(TriggerChanged(int)));
QWidget::connect(time, SIGNAL(timeChanged(const QTime &)), this, QWidget::connect(time, SIGNAL(timeChanged(const QTime &)), this,
@@ -252,19 +245,14 @@ TimeSwitchWidget::TimeSwitchWidget(TimeSwitch *s) : SwitchWidget(s)
time->setTime(s->time); time->setTime(s->time);
} }
setStyleSheet("* { background-color: transparent; }");
QHBoxLayout *mainLayout = new QHBoxLayout; QHBoxLayout *mainLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
mainLayout->addWidget(triggers); {"{{triggers}}", triggers},
mainLayout->addWidget(atLabel); {"{{time}}", time},
mainLayout->addWidget(time); {"{{scenes}}", scenes},
mainLayout->addWidget(switchLabel); {"{{transitions}}", transitions}};
mainLayout->addWidget(scenes); placeWidgets(obs_module_text("AdvSceneSwitcher.timeTab.entry"),
mainLayout->addWidget(usingLabel); mainLayout, widgetPlaceholders);
mainLayout->addWidget(transitions);
mainLayout->addStretch();
setLayout(mainLayout); setLayout(mainLayout);
switchData = s; switchData = s;

View File

@@ -1,18 +1,16 @@
#include "headers/advanced-scene-switcher.hpp" #include "headers/advanced-scene-switcher.hpp"
#include "headers/utility.hpp" #include "headers/utility.hpp"
bool DefaultSceneTransition::pause = false;
void AdvSceneSwitcher::on_transitionsAdd_clicked() void AdvSceneSwitcher::on_transitionsAdd_clicked()
{ {
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->sceneTransitions.emplace_back(); switcher->sceneTransitions.emplace_back();
QListWidgetItem *item; listAddClicked(
item = new QListWidgetItem(ui->sceneTransitions); ui->sceneTransitions,
ui->sceneTransitions->addItem(item); new TransitionSwitchWidget(&switcher->sceneTransitions.back()));
TransitionSwitchWidget *sw =
new TransitionSwitchWidget(&switcher->sceneTransitions.back());
item->setSizeHint(sw->minimumSizeHint());
ui->sceneTransitions->setItemWidget(item, sw);
} }
void AdvSceneSwitcher::on_transitionsRemove_clicked() void AdvSceneSwitcher::on_transitionsRemove_clicked()
@@ -77,13 +75,9 @@ void AdvSceneSwitcher::on_defaultTransitionsAdd_clicked()
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->defaultSceneTransitions.emplace_back(); switcher->defaultSceneTransitions.emplace_back();
QListWidgetItem *item; listAddClicked(ui->defaultTransitions,
item = new QListWidgetItem(ui->defaultTransitions); new DefTransitionSwitchWidget(
ui->defaultTransitions->addItem(item); &switcher->defaultSceneTransitions.back()));
DefTransitionSwitchWidget *sw = new DefTransitionSwitchWidget(
&switcher->defaultSceneTransitions.back());
item->setSizeHint(sw->minimumSizeHint());
ui->defaultTransitions->setItemWidget(item, sw);
} }
void AdvSceneSwitcher::on_defaultTransitionsRemove_clicked() void AdvSceneSwitcher::on_defaultTransitionsRemove_clicked()
@@ -146,7 +140,7 @@ void AdvSceneSwitcher::on_defaultTransitionsDown_clicked()
void SwitcherData::checkDefaultSceneTransitions(bool &match, void SwitcherData::checkDefaultSceneTransitions(bool &match,
OBSWeakSource &transition) OBSWeakSource &transition)
{ {
if (checkedDefTransition) if (checkedDefTransition || DefaultSceneTransition::pause)
return; return;
obs_source_t *currentSource = obs_frontend_get_current_scene(); obs_source_t *currentSource = obs_frontend_get_current_scene();
@@ -418,10 +412,6 @@ TransitionSwitchWidget::TransitionSwitchWidget(SceneTransition *s)
{ {
scenes2 = new QComboBox(); scenes2 = new QComboBox();
switchLabel = new QLabel("Switch from scene");
toLabel = new QLabel("to scene");
usingLabel = new QLabel("using transition");
QWidget::connect(scenes2, SIGNAL(currentTextChanged(const QString &)), QWidget::connect(scenes2, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(Scene2Changed(const QString &))); this, SLOT(Scene2Changed(const QString &)));
@@ -431,18 +421,13 @@ TransitionSwitchWidget::TransitionSwitchWidget(SceneTransition *s)
scenes2->setCurrentText(GetWeakSourceName(s->scene2).c_str()); scenes2->setCurrentText(GetWeakSourceName(s->scene2).c_str());
} }
setStyleSheet("* { background-color: transparent; }");
QHBoxLayout *mainLayout = new QHBoxLayout; QHBoxLayout *mainLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
mainLayout->addWidget(switchLabel); {"{{scenes}}", scenes},
mainLayout->addWidget(scenes); {"{{scenes2}}", scenes2},
mainLayout->addWidget(toLabel); {"{{transitions}}", transitions}};
mainLayout->addWidget(scenes2); placeWidgets(obs_module_text("AdvSceneSwitcher.transitionTab.entry"),
mainLayout->addWidget(usingLabel); mainLayout, widgetPlaceholders);
mainLayout->addWidget(transitions);
mainLayout->addStretch();
setLayout(mainLayout); setLayout(mainLayout);
switchData = s; switchData = s;
@@ -481,20 +466,13 @@ void TransitionSwitchWidget::Scene2Changed(const QString &text)
DefTransitionSwitchWidget::DefTransitionSwitchWidget(DefaultSceneTransition *s) DefTransitionSwitchWidget::DefTransitionSwitchWidget(DefaultSceneTransition *s)
: SwitchWidget(s, false) : SwitchWidget(s, false)
{ {
whenLabel = new QLabel("When scene");
switchLabel =
new QLabel("is active change default scene transition to ");
setStyleSheet("* { background-color: transparent; }");
QHBoxLayout *mainLayout = new QHBoxLayout; QHBoxLayout *mainLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
mainLayout->addWidget(whenLabel); {"{{scenes}}", scenes}, {"{{transitions}}", transitions}};
mainLayout->addWidget(scenes); placeWidgets(
mainLayout->addWidget(switchLabel); obs_module_text(
mainLayout->addWidget(transitions); "AdvSceneSwitcher.transitionTab.defaultTransitionEntry"),
mainLayout->addStretch(); mainLayout, widgetPlaceholders);
setLayout(mainLayout); setLayout(mainLayout);
switchData = s; switchData = s;

View File

@@ -1,22 +1,17 @@
#include "headers/advanced-scene-switcher.hpp" #include "headers/advanced-scene-switcher.hpp"
#include "headers/utility.hpp" #include "headers/utility.hpp"
bool WindowSwitch::pause = false;
static QMetaObject::Connection addPulse; static QMetaObject::Connection addPulse;
void AdvSceneSwitcher::on_windowAdd_clicked() void AdvSceneSwitcher::on_windowAdd_clicked()
{ {
ui->windowAdd->disconnect(addPulse);
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
switcher->windowSwitches.emplace_back(); switcher->windowSwitches.emplace_back();
QListWidgetItem *item; listAddClicked(ui->windowSwitches,
item = new QListWidgetItem(ui->windowSwitches); new WindowSwitchWidget(&switcher->windowSwitches.back()),
ui->windowSwitches->addItem(item); ui->windowAdd, &addPulse);
WindowSwitchWidget *sw =
new WindowSwitchWidget(&switcher->windowSwitches.back());
item->setSizeHint(sw->minimumSizeHint());
ui->windowSwitches->setItemWidget(item, sw);
} }
void AdvSceneSwitcher::on_windowRemove_clicked() void AdvSceneSwitcher::on_windowRemove_clicked()
@@ -193,6 +188,9 @@ bool isFocused(std::string &title)
void SwitcherData::checkWindowTitleSwitch(bool &match, OBSWeakSource &scene, void SwitcherData::checkWindowTitleSwitch(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition) OBSWeakSource &transition)
{ {
if (WindowSwitch::pause)
return;
std::string title; std::string title;
bool ignored = false; bool ignored = false;
@@ -373,9 +371,12 @@ void AdvSceneSwitcher::setupTitleTab()
WindowSwitchWidget::WindowSwitchWidget(WindowSwitch *s) : SwitchWidget(s, false) WindowSwitchWidget::WindowSwitchWidget(WindowSwitch *s) : SwitchWidget(s, false)
{ {
windows = new QComboBox(); windows = new QComboBox();
fullscreen = new QCheckBox("if fullscreen"); fullscreen = new QCheckBox(
maximized = new QCheckBox("if maximized"); obs_module_text("AdvSceneSwitcher.windowTitleTab.fullscreen"));
focused = new QCheckBox("if focused"); maximized = new QCheckBox(
obs_module_text("AdvSceneSwitcher.windowTitleTab.maximized"));
focused = new QCheckBox(
obs_module_text("AdvSceneSwitcher.windowTitleTab.focused"));
QWidget::connect(windows, SIGNAL(currentTextChanged(const QString &)), QWidget::connect(windows, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(WindowChanged(const QString &))); this, SLOT(WindowChanged(const QString &)));
@@ -404,19 +405,16 @@ WindowSwitchWidget::WindowSwitchWidget(WindowSwitch *s) : SwitchWidget(s, false)
focused->setChecked(s->focus); focused->setChecked(s->focus);
} }
setStyleSheet("* { background-color: transparent; }");
QHBoxLayout *mainLayout = new QHBoxLayout; QHBoxLayout *mainLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
mainLayout->addWidget(windows); {"{{windows}}", windows},
mainLayout->addWidget(scenes); {"{{scenes}}", scenes},
mainLayout->addWidget(transitions); {"{{transitions}}", transitions},
mainLayout->addWidget(scenes); {"{{fullscreen}}", fullscreen},
mainLayout->addWidget(fullscreen); {"{{maximized}}", maximized},
mainLayout->addWidget(maximized); {"{{focused}}", focused}};
mainLayout->addWidget(focused); placeWidgets(obs_module_text("AdvSceneSwitcher.windowTitleTab.entry"),
mainLayout->addStretch(); mainLayout, widgetPlaceholders);
setLayout(mainLayout); setLayout(mainLayout);
switchData = s; switchData = s;

View File

@@ -27,11 +27,10 @@ void SwitcherData::Prune()
screenRegionSwitches.begin() + i--); screenRegionSwitches.begin() + i--);
} }
for (size_t i = 0; i < pauseScenesSwitches.size(); i++) { for (size_t i = 0; i < pauseEntries.size(); i++) {
OBSWeakSource &scene = pauseScenesSwitches[i]; PauseEntry &s = pauseEntries[i];
if (!WeakSourceValid(scene)) if (!s.valid())
pauseScenesSwitches.erase(pauseScenesSwitches.begin() + pauseEntries.erase(pauseEntries.begin() + i--);
i--);
} }
for (size_t i = 0; i < sceneSequenceSwitches.size(); i++) { for (size_t i = 0; i < sceneSequenceSwitches.size(); i++) {