mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-08-29 12:45:28 -05:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8727a65513 | ||
|
|
baf3d0e63c | ||
|
|
ea2d1e7e9d | ||
|
|
f9f26ad50b | ||
|
|
9911c41a35 | ||
|
|
d590bc11f8 | ||
|
|
31c4c1f5d7 | ||
|
|
42ff48d637 |
90
.github/scripts/Package-Windows.ps1
vendored
90
.github/scripts/Package-Windows.ps1
vendored
@@ -68,44 +68,53 @@ function Package {
|
||||
|
||||
Remove-Item @RemoveArgs
|
||||
|
||||
# Build a staging directory with two subfolders:
|
||||
# recommended/ - new layout, extract to %ProgramData%\obs-studio\
|
||||
# legacy/ - old layout, extract to the OBS install directory
|
||||
$ReleasePath = "${ProjectRoot}/release/${Configuration}"
|
||||
$StagingPath = "${ProjectRoot}/release/zip-staging"
|
||||
$NewBinPath = "${ReleasePath}/${ProductName}/bin/64bit"
|
||||
$NewDataPath = "${ReleasePath}/${ProductName}/data"
|
||||
|
||||
Remove-Item -Path $StagingPath -Recurse -Force -ErrorAction SilentlyContinue
|
||||
New-Item -ItemType Directory -Force -Path $StagingPath | Out-Null
|
||||
Copy-Item -Path "${ProjectRoot}/build-aux/CI/windows/README.txt" -Destination "${StagingPath}/README.txt"
|
||||
$ReleasePath = "${ProjectRoot}/release/${Configuration}"
|
||||
$NewBinPath = "${ReleasePath}/${ProductName}/bin/64bit"
|
||||
$NewDataPath = "${ReleasePath}/${ProductName}/data"
|
||||
$CIWindowsDir = "${ProjectRoot}/build-aux/CI/windows"
|
||||
|
||||
# --- Recommended zip (new layout, extract to %ProgramData%\obs-studio\) ---
|
||||
Log-Group "Archiving ${ProductName} (recommended)..."
|
||||
$RecStaging = "${ProjectRoot}/release/zip-staging-rec"
|
||||
Remove-Item -Path $RecStaging -Recurse -Force -ErrorAction SilentlyContinue
|
||||
New-Item -ItemType Directory -Force -Path $RecStaging | Out-Null
|
||||
Copy-Item -Path "${CIWindowsDir}/README.txt" -Destination "${RecStaging}/README.txt"
|
||||
if ( Test-Path -Path $NewBinPath ) {
|
||||
$RecBinPath = "${StagingPath}/recommended/${ProductName}/bin/64bit"
|
||||
$LegacyBinPath = "${StagingPath}/legacy/obs-plugins/64bit"
|
||||
New-Item -ItemType Directory -Force -Path $RecBinPath | Out-Null
|
||||
New-Item -ItemType Directory -Force -Path $LegacyBinPath | Out-Null
|
||||
Copy-Item -Path "${NewBinPath}/*" -Destination $RecBinPath -Recurse -Force
|
||||
Copy-Item -Path "${NewBinPath}/*" -Destination $LegacyBinPath -Recurse -Force
|
||||
$RecBinPath = "${RecStaging}/${ProductName}/bin/64bit"
|
||||
New-Item -ItemType Directory -Force -Path $RecBinPath | Out-Null
|
||||
Copy-Item -Path "${NewBinPath}/*" -Destination $RecBinPath -Recurse -Force
|
||||
}
|
||||
if ( Test-Path -Path $NewDataPath ) {
|
||||
$RecDataPath = "${StagingPath}/recommended/${ProductName}/data"
|
||||
$LegacyDataPath = "${StagingPath}/legacy/data/obs-plugins/${ProductName}"
|
||||
New-Item -ItemType Directory -Force -Path $RecDataPath | Out-Null
|
||||
New-Item -ItemType Directory -Force -Path $LegacyDataPath | Out-Null
|
||||
Copy-Item -Path "${NewDataPath}/*" -Destination $RecDataPath -Recurse -Force
|
||||
Copy-Item -Path "${NewDataPath}/*" -Destination $LegacyDataPath -Recurse -Force
|
||||
$RecDataPath = "${RecStaging}/${ProductName}/data"
|
||||
New-Item -ItemType Directory -Force -Path $RecDataPath | Out-Null
|
||||
Copy-Item -Path "${NewDataPath}/*" -Destination $RecDataPath -Recurse -Force
|
||||
}
|
||||
Compress-Archive -Force -Path (Get-ChildItem -Path $RecStaging) `
|
||||
-CompressionLevel Optimal `
|
||||
-DestinationPath "${ProjectRoot}/release/${OutputName}.zip"
|
||||
Remove-Item -Path $RecStaging -Recurse -Force
|
||||
Log-Group
|
||||
|
||||
Log-Group "Archiving ${ProductName}..."
|
||||
$CompressArgs = @{
|
||||
Path = (Get-ChildItem -Path $StagingPath)
|
||||
CompressionLevel = 'Optimal'
|
||||
DestinationPath = "${ProjectRoot}/release/${OutputName}.zip"
|
||||
Verbose = ($null -ne $Env:CI)
|
||||
# --- Legacy zip (old layout, extract to OBS install directory) ---
|
||||
Log-Group "Archiving ${ProductName} (legacy)..."
|
||||
$LegStaging = "${ProjectRoot}/release/zip-staging-leg"
|
||||
Remove-Item -Path $LegStaging -Recurse -Force -ErrorAction SilentlyContinue
|
||||
New-Item -ItemType Directory -Force -Path $LegStaging | Out-Null
|
||||
Copy-Item -Path "${CIWindowsDir}/README-legacy.txt" -Destination "${LegStaging}/README.txt"
|
||||
if ( Test-Path -Path $NewBinPath ) {
|
||||
$LegBinPath = "${LegStaging}/obs-plugins/64bit"
|
||||
New-Item -ItemType Directory -Force -Path $LegBinPath | Out-Null
|
||||
Copy-Item -Path "${NewBinPath}/*" -Destination $LegBinPath -Recurse -Force
|
||||
}
|
||||
Compress-Archive -Force @CompressArgs
|
||||
Remove-Item -Path $StagingPath -Recurse -Force
|
||||
if ( Test-Path -Path $NewDataPath ) {
|
||||
$LegDataPath = "${LegStaging}/data/obs-plugins/${ProductName}"
|
||||
New-Item -ItemType Directory -Force -Path $LegDataPath | Out-Null
|
||||
Copy-Item -Path "${NewDataPath}/*" -Destination $LegDataPath -Recurse -Force
|
||||
}
|
||||
Compress-Archive -Force -Path (Get-ChildItem -Path $LegStaging) `
|
||||
-CompressionLevel Optimal `
|
||||
-DestinationPath "${ProjectRoot}/release/${OutputName}-legacy.zip"
|
||||
Remove-Item -Path $LegStaging -Recurse -Force
|
||||
Log-Group
|
||||
|
||||
if ( ( $BuildInstaller ) ) {
|
||||
@@ -120,7 +129,24 @@ function Package {
|
||||
Push-Location -Stack BuildTemp
|
||||
Ensure-Location -Path "${ProjectRoot}/release"
|
||||
Remove-Item -Path Package -Recurse -Force -ErrorAction SilentlyContinue
|
||||
Copy-Item -Path ${Configuration} -Destination Package -Recurse
|
||||
|
||||
# Recommended layout (for %ProgramData%\obs-studio\plugins\)
|
||||
$PkgRec = "Package/recommended"
|
||||
New-Item -ItemType Directory -Force -Path $PkgRec | Out-Null
|
||||
Copy-Item -Path "${Configuration}/*" -Destination $PkgRec -Recurse -Force
|
||||
|
||||
# Legacy layout (for OBS installation directory)
|
||||
if ( Test-Path "${Configuration}/${ProductName}/bin/64bit" ) {
|
||||
$PkgLegBin = "Package/legacy/obs-plugins/64bit"
|
||||
New-Item -ItemType Directory -Force -Path $PkgLegBin | Out-Null
|
||||
Copy-Item -Path "${Configuration}/${ProductName}/bin/64bit/*" -Destination $PkgLegBin -Recurse -Force
|
||||
}
|
||||
if ( Test-Path "${Configuration}/${ProductName}/data" ) {
|
||||
$PkgLegData = "Package/legacy/data/obs-plugins/${ProductName}"
|
||||
New-Item -ItemType Directory -Force -Path $PkgLegData | Out-Null
|
||||
Copy-Item -Path "${Configuration}/${ProductName}/data/*" -Destination $PkgLegData -Recurse -Force
|
||||
}
|
||||
|
||||
Invoke-External iscc ${IsccFile} /O"${ProjectRoot}/release" /F"${OutputName}-Installer"
|
||||
Remove-Item -Path Package -Recurse
|
||||
Pop-Location -Stack BuildTemp
|
||||
|
||||
23
build-aux/CI/windows/README-legacy.txt
Normal file
23
build-aux/CI/windows/README-legacy.txt
Normal file
@@ -0,0 +1,23 @@
|
||||
Advanced Scene Switcher - Windows Installation (Legacy)
|
||||
========================================================
|
||||
|
||||
For full installation instructions visit:
|
||||
https://github.com/WarmUpTill/SceneSwitcher/wiki/Installation
|
||||
|
||||
|
||||
This archive uses the legacy plugin layout for older OBS versions,
|
||||
portable OBS installs, and Steam.
|
||||
|
||||
Extract the CONTENTS of this archive into your OBS installation directory,
|
||||
typically:
|
||||
|
||||
C:\Program Files\obs-studio\
|
||||
|
||||
Merge the data\ and obs-plugins\ folders with the existing ones when prompted.
|
||||
|
||||
Steam users: right-click OBS in your library -> Manage -> Browse local files,
|
||||
then extract the contents of this archive into that directory.
|
||||
|
||||
|
||||
For OBS 28 and newer the recommended archive is preferred:
|
||||
advanced-scene-switcher-<version>-windows-x64.zip
|
||||
@@ -1,22 +1,15 @@
|
||||
Advanced Scene Switcher - Windows Installation
|
||||
==============================================
|
||||
===============================================
|
||||
|
||||
For full installation instructions visit:
|
||||
https://github.com/WarmUpTill/SceneSwitcher/wiki/Installation
|
||||
|
||||
|
||||
Quick guide
|
||||
-----------
|
||||
This archive uses the recommended plugin layout for OBS 28 and newer.
|
||||
|
||||
This archive contains two installation methods.
|
||||
Choose ONE depending on your OBS version.
|
||||
Extract the CONTENTS of this archive into:
|
||||
|
||||
|
||||
recommended\ (preferred)
|
||||
---------------------------------------------
|
||||
Extract the CONTENTS of this folder into:
|
||||
|
||||
C:\ProgramData\obs-studio\
|
||||
C:\ProgramData\obs-studio\plugins\
|
||||
|
||||
Tip: press Win+R and type %ProgramData%\obs-studio\plugins to open that folder.
|
||||
|
||||
@@ -24,14 +17,5 @@ After extracting, the path should look like:
|
||||
C:\ProgramData\obs-studio\plugins\advanced-scene-switcher\bin\64bit\advanced-scene-switcher.dll
|
||||
|
||||
|
||||
legacy\ (older OBS versions, portable OBS installs, or if the recommended method does not work)
|
||||
---------------------------------------------------------------------------
|
||||
Extract the CONTENTS of this folder into your OBS installation directory,
|
||||
typically:
|
||||
|
||||
C:\Program Files\obs-studio\
|
||||
|
||||
Merge the data\ and obs-plugins\ folders with the existing ones when prompted.
|
||||
|
||||
Steam users: right-click OBS in your library -> Manage -> Browse local files,
|
||||
then extract the contents of legacy\ into that directory.
|
||||
If the plugin does not appear in OBS, try the legacy archive instead:
|
||||
advanced-scene-switcher-<version>-windows-x64-legacy.zip
|
||||
|
||||
@@ -23,14 +23,17 @@ SolidCompression=yes
|
||||
DirExistsWarning=no
|
||||
UsePreviousAppDir=no
|
||||
SetupIconFile=installer.ico
|
||||
UninstallDisplayIcon={app}\advanced-scene-switcher\data\res\images\logo.ico
|
||||
UninstallDisplayIcon={code:GetUninstallIconPath}
|
||||
DisableDirPage=no
|
||||
|
||||
[Languages]
|
||||
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||
|
||||
[Files]
|
||||
Source: "..\release\Package\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||
; Recommended layout - used when installing to %ProgramData%\obs-studio\plugins\
|
||||
Source: "..\release\Package\recommended\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs; Check: IsRecommendedLayout
|
||||
; Legacy layout - used when installing to the OBS installation directory
|
||||
Source: "..\release\Package\legacy\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs; Check: IsLegacyLayout
|
||||
Source: "..\LICENSE"; Flags: dontcopy
|
||||
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
|
||||
|
||||
@@ -53,23 +56,54 @@ begin
|
||||
);
|
||||
end;
|
||||
|
||||
// Returns true when the selected install directory is under %ProgramData%,
|
||||
// meaning the recommended plugin layout should be used.
|
||||
function IsRecommendedLayout(): Boolean;
|
||||
begin
|
||||
Result := Pos(LowerCase(ExpandConstant('{commonappdata}')),
|
||||
LowerCase(WizardDirValue())) = 1;
|
||||
end;
|
||||
|
||||
function IsLegacyLayout(): Boolean;
|
||||
begin
|
||||
Result := not IsRecommendedLayout();
|
||||
end;
|
||||
|
||||
function GetUninstallIconPath(Param: string): string;
|
||||
begin
|
||||
if IsRecommendedLayout() then
|
||||
Result := ExpandConstant('{app}\advanced-scene-switcher\data\res\images\logo.ico')
|
||||
else
|
||||
Result := ExpandConstant('{app}\data\obs-plugins\advanced-scene-switcher\res\images\logo.ico');
|
||||
end;
|
||||
|
||||
function GetDirName(Value: string): string;
|
||||
var
|
||||
PrevPath: string;
|
||||
UninstallKey: string;
|
||||
begin
|
||||
Result := ExpandConstant('{commonappdata}\obs-studio\plugins');
|
||||
UninstallKey := 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' + '{' + '{#MyAppId}' + '}_is1';
|
||||
if RegQueryStringValue(HKLM, UninstallKey, 'InstallLocation', PrevPath) and (PrevPath <> '') then
|
||||
Result := PrevPath;
|
||||
end;
|
||||
|
||||
// Remove files placed by the legacy installer (obs-plugins/64bit and
|
||||
// data/obs-plugins layout) so the plugin is not loaded twice by OBS.
|
||||
// We read InstallLocation from our own previous uninstall entry, which is
|
||||
// the exact directory the old installer used regardless of OBS install path.
|
||||
// Only runs when upgrading from a legacy location to the recommended one.
|
||||
procedure RemoveLegacyFiles();
|
||||
var
|
||||
OldInstallPath: string;
|
||||
UninstallKey: string;
|
||||
begin
|
||||
if not IsRecommendedLayout() then
|
||||
Exit;
|
||||
UninstallKey := 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' + '{' + '{#MyAppId}' + '}_is1';
|
||||
if not RegQueryStringValue(HKLM, UninstallKey, 'InstallLocation', OldInstallPath) then
|
||||
Exit;
|
||||
// Skip if the previous install was already in the recommended location
|
||||
if Pos(LowerCase(ExpandConstant('{commonappdata}')), LowerCase(OldInstallPath)) = 1 then
|
||||
Exit;
|
||||
DeleteFile(OldInstallPath + '\obs-plugins\64bit\advanced-scene-switcher.dll');
|
||||
DeleteFile(OldInstallPath + '\obs-plugins\64bit\advanced-scene-switcher.pdb');
|
||||
DeleteFile(OldInstallPath + '\obs-plugins\64bit\advanced-scene-switcher-lib.dll');
|
||||
@@ -83,4 +117,3 @@ begin
|
||||
if CurStep = ssInstall then
|
||||
RemoveLegacyFiles();
|
||||
end;
|
||||
|
||||
|
||||
@@ -47,6 +47,13 @@ AdvSceneSwitcher.generalTab.generalBehavior.hideLegacyTabs="Hide tabs which can
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.alwaysShowMacroSearch="Always show macro search"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.alwaysShowFeatureTabs="Always show all feature tabs"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.alwaysShowFeatureTabs.tooltip="Show tabs that are normally hidden until first used in a macro (e.g. Action Queues, Variables, Twitch, Websockets)."
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.settingsLock="Lock settings dialog with password"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.title="Settings Locked"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.passwordLabel="Enter password:"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.wrongPassword="Wrong password!"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.newPasswordLabel="New password:"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.confirmPasswordLabel="Confirm password:"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.passwordMismatch="Passwords do not match!"
|
||||
AdvSceneSwitcher.generalTab.matchBehavior="Match behavior"
|
||||
AdvSceneSwitcher.generalTab.priority="Priority"
|
||||
AdvSceneSwitcher.generalTab.priority.description="Switching methods priority (Highest priority is at the top)"
|
||||
|
||||
@@ -258,6 +258,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="settingsLock">
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.generalTab.generalBehavior.settingsLock</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -19,8 +19,10 @@
|
||||
#include <obs-frontend-api.h>
|
||||
#include <QAction>
|
||||
#include <QDirIterator>
|
||||
#include <QInputDialog>
|
||||
#include <QLibrary>
|
||||
#include <QMainWindow>
|
||||
#include <QMessageBox>
|
||||
#include <QTextStream>
|
||||
#include <regex>
|
||||
|
||||
@@ -459,12 +461,13 @@ void SwitcherData::Stop()
|
||||
SetMacroAbortWait(true);
|
||||
GetMacroWaitCV().notify_all();
|
||||
GetMacroTransitionCV().notify_all();
|
||||
StopAllMacros();
|
||||
SignalStopAllMacros();
|
||||
StopAndClearAllActionQueues();
|
||||
CloseAllInputDialogs();
|
||||
th->wait();
|
||||
delete th;
|
||||
th = nullptr;
|
||||
WaitForAllMacros();
|
||||
RunStopSteps();
|
||||
}
|
||||
|
||||
@@ -718,19 +721,54 @@ static void LoadPlugins()
|
||||
}
|
||||
}
|
||||
|
||||
static bool settingsPasswordIsCorrect(QWidget *parent)
|
||||
{
|
||||
bool ok;
|
||||
QString input = QInputDialog::getText(
|
||||
parent,
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.title"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.passwordLabel"),
|
||||
QLineEdit::Password, QString(), &ok);
|
||||
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (input.toStdString() == switcher->settingsLockPassword) {
|
||||
return true;
|
||||
}
|
||||
|
||||
QMessageBox::warning(
|
||||
parent,
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.title"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.wrongPassword"));
|
||||
return false;
|
||||
}
|
||||
|
||||
void OpenSettingsWindow()
|
||||
{
|
||||
if (switcher->settingsWindowOpened) {
|
||||
AdvSceneSwitcher::window->show();
|
||||
AdvSceneSwitcher::window->raise();
|
||||
AdvSceneSwitcher::window->activateWindow();
|
||||
} else {
|
||||
AdvSceneSwitcher::window =
|
||||
new AdvSceneSwitcher(static_cast<QMainWindow *>(
|
||||
obs_frontend_get_main_window()));
|
||||
AdvSceneSwitcher::window->setAttribute(Qt::WA_DeleteOnClose);
|
||||
AdvSceneSwitcher::window->show();
|
||||
return;
|
||||
}
|
||||
|
||||
auto parent =
|
||||
static_cast<QMainWindow *>(obs_frontend_get_main_window());
|
||||
if (switcher->settingsLockEnabled &&
|
||||
!switcher->settingsLockPassword.empty() &&
|
||||
!settingsPasswordIsCorrect(parent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
AdvSceneSwitcher::window = new AdvSceneSwitcher(parent);
|
||||
AdvSceneSwitcher::window->setAttribute(Qt::WA_DeleteOnClose);
|
||||
AdvSceneSwitcher::window->show();
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::HighlightMacroSettingsButton(bool enable)
|
||||
|
||||
@@ -68,6 +68,7 @@ public slots:
|
||||
void on_warnPluginLoadFailure_stateChanged(int state);
|
||||
void on_suppressCrashRecoveryDialog_stateChanged(int state);
|
||||
void on_hideLegacyTabs_stateChanged(int state);
|
||||
void on_settingsLock_stateChanged(int state);
|
||||
void on_priorityUp_clicked();
|
||||
void on_priorityDown_clicked();
|
||||
void on_threadPriority_currentTextChanged(const QString &text);
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
#include <obs-frontend-api.h>
|
||||
#include <QFileDialog>
|
||||
#include <QInputDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
namespace advss {
|
||||
|
||||
@@ -243,6 +245,64 @@ void AdvSceneSwitcher::on_hideLegacyTabs_stateChanged(int state)
|
||||
ui->priorityBox->setVisible(!switcher->hideLegacyTabs);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_settingsLock_stateChanged(int state)
|
||||
{
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!state) {
|
||||
switcher->settingsLockEnabled = false;
|
||||
switcher->settingsLockPassword = "";
|
||||
return;
|
||||
}
|
||||
|
||||
bool ok;
|
||||
QString newPassword = QInputDialog::getText(
|
||||
this,
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.title"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.newPasswordLabel"),
|
||||
QLineEdit::Password, QString(), &ok);
|
||||
|
||||
const auto disablePassword = [this]() {
|
||||
QSignalBlocker blocker(ui->settingsLock);
|
||||
ui->settingsLock->setChecked(false);
|
||||
ui->settingsLock->setCheckState(Qt::Unchecked);
|
||||
switcher->settingsLockEnabled = false;
|
||||
switcher->settingsLockPassword = "";
|
||||
};
|
||||
|
||||
if (!ok || newPassword.isEmpty()) {
|
||||
disablePassword();
|
||||
return;
|
||||
}
|
||||
|
||||
QString confirm = QInputDialog::getText(
|
||||
this,
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.title"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.confirmPasswordLabel"),
|
||||
QLineEdit::Password, QString(), &ok);
|
||||
if (!ok || newPassword != confirm) {
|
||||
if (ok) {
|
||||
QMessageBox::warning(
|
||||
this,
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.title"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.passwordMismatch"));
|
||||
}
|
||||
disablePassword();
|
||||
return;
|
||||
}
|
||||
|
||||
switcher->settingsLockEnabled = true;
|
||||
switcher->settingsLockPassword = newPassword.toStdString();
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::SetDeprecationWarnings()
|
||||
{
|
||||
QString toolTip =
|
||||
@@ -567,6 +627,9 @@ void SwitcherData::SaveGeneralSettings(obs_data_t *obj)
|
||||
disableFilterComboboxFilter);
|
||||
obs_data_set_bool(obj, "warnPluginLoadFailure", warnPluginLoadFailure);
|
||||
obs_data_set_bool(obj, "hideLegacyTabs", hideLegacyTabs);
|
||||
obs_data_set_bool(obj, "settingsLockEnabled", settingsLockEnabled);
|
||||
obs_data_set_string(obj, "settingsLockPassword",
|
||||
settingsLockPassword.c_str());
|
||||
|
||||
SaveFunctionPriorities(obj, functionNamesByPriority);
|
||||
|
||||
@@ -638,6 +701,8 @@ void SwitcherData::LoadGeneralSettings(obs_data_t *obj)
|
||||
warnPluginLoadFailure = obs_data_get_bool(obj, "warnPluginLoadFailure");
|
||||
obs_data_set_default_bool(obj, "hideLegacyTabs", true);
|
||||
hideLegacyTabs = obs_data_get_bool(obj, "hideLegacyTabs");
|
||||
settingsLockEnabled = obs_data_get_bool(obj, "settingsLockEnabled");
|
||||
settingsLockPassword = obs_data_get_string(obj, "settingsLockPassword");
|
||||
|
||||
SetDefaultFunctionPriorities(obj);
|
||||
LoadFunctionPriorities(obj, functionNamesByPriority);
|
||||
@@ -960,6 +1025,7 @@ void AdvSceneSwitcher::SetupGeneralTab()
|
||||
ui->warnPluginLoadFailure->setChecked(switcher->warnPluginLoadFailure);
|
||||
ui->suppressCrashRecoveryDialog->setChecked(GetSuppressCrashDialog());
|
||||
ui->hideLegacyTabs->setChecked(switcher->hideLegacyTabs);
|
||||
ui->settingsLock->setChecked(switcher->settingsLockEnabled);
|
||||
|
||||
populatePriorityFunctionList(ui->priorityList);
|
||||
populateThreadPriorityList(ui->threadPriority);
|
||||
|
||||
@@ -76,7 +76,8 @@ EXPORT bool RunMacroElseActions(Macro *, bool forceParallel = false,
|
||||
bool ignorePause = false);
|
||||
EXPORT bool RunMacros();
|
||||
|
||||
void StopAllMacros();
|
||||
void SignalStopAllMacros();
|
||||
void WaitForAllMacros();
|
||||
|
||||
EXPORT void LoadMacros(obs_data_t *obj);
|
||||
EXPORT void SaveMacros(obs_data_t *obj);
|
||||
|
||||
@@ -395,7 +395,7 @@ void AdvSceneSwitcher::ImportMacros()
|
||||
std::vector<std::shared_ptr<Macro>> importedMacros;
|
||||
auto &tempMacros = GetTemporaryMacros();
|
||||
|
||||
auto lock = LockContext();
|
||||
std::unique_lock<std::mutex> lock(*GetMutex());
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
tempMacros.clear();
|
||||
|
||||
@@ -405,10 +405,14 @@ void AdvSceneSwitcher::ImportMacros()
|
||||
macro->Load(array_obj);
|
||||
RunAndClearPostLoadSteps();
|
||||
|
||||
if (macroNameExists(macro->Name()) &&
|
||||
!ResolveMacroImportNameConflict(macro)) {
|
||||
groupSize--;
|
||||
continue;
|
||||
if (macroNameExists(macro->Name())) {
|
||||
lock.unlock();
|
||||
bool resolved = ResolveMacroImportNameConflict(macro);
|
||||
lock.lock();
|
||||
if (!resolved) {
|
||||
groupSize--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
importedMacros.emplace_back(macro);
|
||||
|
||||
@@ -1316,7 +1316,14 @@ bool RunMacros()
|
||||
return true;
|
||||
}
|
||||
|
||||
void StopAllMacros()
|
||||
void SignalStopAllMacros()
|
||||
{
|
||||
for (const auto &m : GetAllMacros()) {
|
||||
m->SignalStop();
|
||||
}
|
||||
}
|
||||
|
||||
void WaitForAllMacros()
|
||||
{
|
||||
for (const auto &m : GetAllMacros()) {
|
||||
m->Stop();
|
||||
|
||||
@@ -61,6 +61,7 @@ public:
|
||||
PauseStateSaveBehavior GetPauseStateSaveBehavior() const;
|
||||
|
||||
void Stop();
|
||||
void SignalStop() { _stop = true; }
|
||||
bool GetStop() const { return _stop; }
|
||||
void ResetTimers();
|
||||
|
||||
@@ -228,7 +229,7 @@ void LoadMacros(obs_data_t *obj);
|
||||
void SaveMacros(obs_data_t *obj);
|
||||
bool CheckMacros();
|
||||
bool RunMacros();
|
||||
void StopAllMacros();
|
||||
void WaitForAllMacros();
|
||||
void InvalidateMacroTempVarValues();
|
||||
std::shared_ptr<Macro> GetMacroWithInvalidConditionInterval();
|
||||
|
||||
|
||||
@@ -163,6 +163,8 @@ public:
|
||||
bool disableHints = false;
|
||||
bool disableFilterComboboxFilter = false;
|
||||
bool hideLegacyTabs = true;
|
||||
bool settingsLockEnabled = false;
|
||||
std::string settingsLockPassword;
|
||||
bool saveWindowGeo = false;
|
||||
QPoint windowPos = {};
|
||||
QSize windowSize = {};
|
||||
|
||||
@@ -262,12 +262,21 @@ std::string EventSub::AddEventSubscription(std::shared_ptr<TwitchToken> token,
|
||||
return "";
|
||||
}
|
||||
|
||||
// Capture the session ID and release the lock before making the HTTP
|
||||
// request. Holding the mutex during a network call would block
|
||||
// SubscriptionIsActive() on the condition-check thread for the entire
|
||||
// duration of the request, causing visibly slow macro evaluations.
|
||||
const std::string sessionID = eventSub->_sessionID;
|
||||
lock.unlock();
|
||||
|
||||
OBSDataAutoRelease postData = copyData(subscription.data);
|
||||
setTransportData(postData.Get(), eventSub->_sessionID);
|
||||
setTransportData(postData.Get(), sessionID);
|
||||
auto result = SendPostRequest(*token, registerSubscriptionURL.data(),
|
||||
registerSubscriptionPath.data(), {},
|
||||
postData.Get());
|
||||
|
||||
lock.lock();
|
||||
|
||||
if (result.status != 202) {
|
||||
const char *error = obs_data_get_string(result.data, "error");
|
||||
const char *message =
|
||||
@@ -280,6 +289,24 @@ std::string EventSub::AddEventSubscription(std::shared_ptr<TwitchToken> token,
|
||||
return "";
|
||||
}
|
||||
|
||||
// Verify the session has not been replaced while the HTTP request was
|
||||
// in flight (e.g. a reconnect occurred). If it was, the subscription
|
||||
// we just created belongs to a dead session and must be discarded so
|
||||
// the caller will retry with the new session ID.
|
||||
if (eventSub->_sessionID != sessionID) {
|
||||
blog(LOG_INFO,
|
||||
"discarding Twitch EventSub registration - session ID "
|
||||
"changed during HTTP request");
|
||||
return "";
|
||||
}
|
||||
|
||||
// Another thread may have registered the same subscription while the
|
||||
// lock was released.
|
||||
if (isAlreadySubscribed(eventSub->_activeSubscriptions, subscription)) {
|
||||
eventSub->LogActiveSubscriptions();
|
||||
return eventSub->_activeSubscriptions.find(subscription)->id;
|
||||
}
|
||||
|
||||
OBSDataArrayAutoRelease replyArray =
|
||||
obs_data_get_array(result.data, "data");
|
||||
OBSDataAutoRelease replyData = obs_data_array_item(replyArray, 0);
|
||||
@@ -439,9 +466,10 @@ void EventSub::OnMessage(connection_hdl, EventSubWSClient::message_ptr message)
|
||||
|
||||
void EventSub::HandleWelcome(obs_data_t *data)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_subscriptionMtx);
|
||||
OBSDataAutoRelease session = obs_data_get_obj(data, "session");
|
||||
_sessionID = obs_data_get_string(session, "id");
|
||||
ClearActiveSubscriptions();
|
||||
_activeSubscriptions.clear();
|
||||
blog(LOG_INFO, "Twitch EventSub connected");
|
||||
vblog(LOG_INFO, "Twitch EventSub session id: %s", _sessionID.c_str());
|
||||
}
|
||||
|
||||
@@ -403,11 +403,12 @@ bool MacroConditionVideo::CheckBrightnessThreshold()
|
||||
|
||||
bool MacroConditionVideo::CheckOCR()
|
||||
{
|
||||
if (!_ocrParameters.Initialized()) {
|
||||
auto *ocr = _ocrParameters.GetOCR();
|
||||
if (!ocr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto text = RunOCR(_ocrParameters.GetOCR(), _screenshotData.GetImage(),
|
||||
auto text = RunOCR(ocr, _screenshotData.GetImage(),
|
||||
_ocrParameters.color, _ocrParameters.colorThreshold);
|
||||
if (!text) {
|
||||
return false;
|
||||
|
||||
@@ -82,7 +82,7 @@ bool ObjDetectParameters::Save(obs_data_t *obj) const
|
||||
minSize.Save(data, "minSize");
|
||||
maxSize.Save(data, "maxSize");
|
||||
obs_data_set_obj(obj, "objectMatchData", data);
|
||||
obs_data_set_int(data, "version", 1);
|
||||
obs_data_set_int(data, "version", 2);
|
||||
obs_data_release(data);
|
||||
return true;
|
||||
}
|
||||
@@ -121,6 +121,21 @@ bool ObjDetectParameters::Load(obs_data_t *obj)
|
||||
// TODO: Remove this fallback in a future version
|
||||
if (!obs_data_has_user_value(data, "version")) {
|
||||
scaleFactor = obs_data_get_double(data, "scaleFactor");
|
||||
} else if (obs_data_get_int(data, "version") == 1) {
|
||||
#ifdef _WIN32
|
||||
// On Windows the plugin directory moved from
|
||||
// "Program Files/.../data/obs-plugins/advanced-scene-switcher"
|
||||
// to "ProgramData/.../plugins/advanced-scene-switcher/data",
|
||||
// which invalidates previously saved default model paths.
|
||||
const std::string oldPrefix =
|
||||
"../../data/obs-plugins/advanced-scene-switcher/res/cascadeClassifiers/";
|
||||
if (modelPath.substr(0, oldPrefix.size()) == oldPrefix) {
|
||||
modelPath = std::string(obs_get_module_data_path(
|
||||
obs_current_module())) +
|
||||
"/res/cascadeClassifiers/" +
|
||||
modelPath.substr(oldPrefix.size());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (scaleFactor.IsFixedType() && !isScaleFactorValid(scaleFactor)) {
|
||||
scaleFactor = 1.1;
|
||||
@@ -303,9 +318,6 @@ OCRParameters::OCRParameters(const OCRParameters &other)
|
||||
useConfig(other.useConfig),
|
||||
configFile(other.configFile)
|
||||
{
|
||||
if (!initDone) {
|
||||
Setup();
|
||||
}
|
||||
}
|
||||
|
||||
OCRParameters &OCRParameters::operator=(const OCRParameters &other)
|
||||
@@ -319,9 +331,7 @@ OCRParameters &OCRParameters::operator=(const OCRParameters &other)
|
||||
languageCode = other.languageCode;
|
||||
useConfig = other.useConfig;
|
||||
configFile = other.configFile;
|
||||
if (!initDone) {
|
||||
Setup();
|
||||
}
|
||||
initDone = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -337,7 +347,7 @@ bool OCRParameters::Save(obs_data_t *obj) const
|
||||
SaveColor(data, "textColor", color);
|
||||
colorThreshold.Save(data, "colorThreshold");
|
||||
obs_data_set_int(data, "pageSegMode", static_cast<int>(pageSegMode));
|
||||
obs_data_set_int(data, "version", 2);
|
||||
obs_data_set_int(data, "version", 3);
|
||||
obs_data_set_obj(obj, "ocrData", data);
|
||||
obs_data_release(data);
|
||||
return true;
|
||||
@@ -356,6 +366,23 @@ bool OCRParameters::Load(obs_data_t *obj)
|
||||
tesseractBasePath = std::string(obs_get_module_data_path(
|
||||
obs_current_module())) +
|
||||
"/res/ocr/";
|
||||
} else if (obs_data_get_int(data, "version") == 2) {
|
||||
#ifdef _WIN32
|
||||
// On Windows the plugin directory moved from
|
||||
// "Program Files/.../data/obs-plugins/advanced-scene-switcher"
|
||||
// to "ProgramData/.../plugins/advanced-scene-switcher/data",
|
||||
// which invalidates the previously saved default OCR path.
|
||||
const std::string oldPath = tesseractBasePath;
|
||||
if (oldPath ==
|
||||
"../../data/obs-plugins/advanced-scene-switcher/res/ocr/" ||
|
||||
oldPath ==
|
||||
"../../data/obs-plugins/advanced-scene-switcher/res/ocr") {
|
||||
tesseractBasePath =
|
||||
std::string(obs_get_module_data_path(
|
||||
obs_current_module())) +
|
||||
"/res/ocr/";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
useConfig = obs_data_get_bool(data, "useConfig");
|
||||
configFile = obs_data_get_string(data, "configFile");
|
||||
@@ -380,6 +407,14 @@ void OCRParameters::SetPageMode(tesseract::PageSegMode mode)
|
||||
}
|
||||
}
|
||||
|
||||
tesseract::TessBaseAPI *OCRParameters::GetOCR()
|
||||
{
|
||||
if (!initDone) {
|
||||
Setup();
|
||||
}
|
||||
return initDone ? ocr.get() : nullptr;
|
||||
}
|
||||
|
||||
bool OCRParameters::SetLanguageCode(const std::string &value)
|
||||
{
|
||||
const auto dataPath = QString::fromStdString(tesseractBasePath) + "/" +
|
||||
@@ -389,7 +424,7 @@ bool OCRParameters::SetLanguageCode(const std::string &value)
|
||||
return false;
|
||||
}
|
||||
languageCode = value;
|
||||
Setup();
|
||||
initDone = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -408,7 +443,7 @@ bool OCRParameters::SetTesseractBasePath(const std::string &value)
|
||||
return false;
|
||||
}
|
||||
tesseractBasePath = value;
|
||||
Setup();
|
||||
initDone = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -420,13 +455,13 @@ std::string OCRParameters::GetTesseractBasePath() const
|
||||
void OCRParameters::EnableCustomConfig(bool enable)
|
||||
{
|
||||
useConfig = enable;
|
||||
Setup();
|
||||
initDone = false;
|
||||
}
|
||||
|
||||
void OCRParameters::SetCustomConfigFile(const std::string &filename)
|
||||
{
|
||||
configFile = filename;
|
||||
Setup();
|
||||
initDone = false;
|
||||
}
|
||||
|
||||
void OCRParameters::Setup()
|
||||
|
||||
@@ -108,10 +108,7 @@ public:
|
||||
void SetCustomConfigFile(const std::string &);
|
||||
std::string GetCustomConfigFile() const { return configFile; }
|
||||
tesseract::PageSegMode GetPageMode() const { return pageSegMode; }
|
||||
tesseract::TessBaseAPI *GetOCR() const
|
||||
{
|
||||
return initDone ? ocr.get() : nullptr;
|
||||
}
|
||||
tesseract::TessBaseAPI *GetOCR();
|
||||
|
||||
StringVariable text = obs_module_text("AdvSceneSwitcher.enterText");
|
||||
RegexConfig regex = RegexConfig::PartialMatchRegexConfig();
|
||||
|
||||
Reference in New Issue
Block a user