diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini
index 141774a1f..06562c37e 100644
--- a/UI/data/locale/en-US.ini
+++ b/UI/data/locale/en-US.ini
@@ -261,6 +261,10 @@ Updater.Running.Title="Program currently active"
Updater.Running.Text="Outputs are currently active, please shut down any active outputs before attempting to update"
Updater.NoUpdatesAvailable.Title="No updates available"
Updater.NoUpdatesAvailable.Text="No updates are currently available"
+Updater.RepairButUpdatesAvailable.Title="Integrity Check Unavailable"
+Updater.RepairButUpdatesAvailable.Text="Checking file integrity is only possible for the latest version available. Use Help → Check For Updates to verify and update your OBS installation."
+Updater.RepairConfirm.Title="Confirm Integrity Check"
+Updater.RepairConfirm.Text="Starting the integrity check will scan your OBS installation for corruption and redownload broken/modified files. This may take a moment.\n\nDo you wish to proceed?"
Updater.FailedToLaunch="Failed to launch updater"
Updater.GameCaptureActive.Title="Game capture active"
Updater.GameCaptureActive.Text="Game capture hook library is currently in use. Please close any games/programs being captured (or restart Windows) and try again."
@@ -781,6 +785,7 @@ Basic.MainMenu.Help.Logs.UploadCurrentLog="Upload &Current Log File"
Basic.MainMenu.Help.Logs.UploadLastLog="Upload &Previous Log File"
Basic.MainMenu.Help.Logs.ViewCurrentLog="&View Current Log"
Basic.MainMenu.Help.CheckForUpdates="Check For Updates"
+Basic.MainMenu.Help.Repair="Check File Integrity"
Basic.MainMenu.Help.CrashLogs="Crash &Reports"
Basic.MainMenu.Help.CrashLogs.ShowLogs="&Show Crash Reports"
Basic.MainMenu.Help.CrashLogs.UploadLastLog="Upload &Previous Crash Report"
diff --git a/UI/forms/OBSBasic.ui b/UI/forms/OBSBasic.ui
index 514d07aa3..a73aec550 100644
--- a/UI/forms/OBSBasic.ui
+++ b/UI/forms/OBSBasic.ui
@@ -532,6 +532,7 @@
+
@@ -1913,6 +1914,11 @@
Basic.MainMenu.Help.CheckForUpdates
+
+
+ Basic.MainMenu.Help.Repair
+
+
Interact
diff --git a/UI/win-update/win-update.cpp b/UI/win-update/win-update.cpp
index 56a7134e8..7619aa6ea 100644
--- a/UI/win-update/win-update.cpp
+++ b/UI/win-update/win-update.cpp
@@ -511,6 +511,25 @@ int AutoUpdateThread::queryUpdate(bool localManualUpdate, const char *text_utf8)
return ret;
}
+bool AutoUpdateThread::queryRepairSlot()
+{
+ QMessageBox::StandardButton res = OBSMessageBox::question(
+ App()->GetMainWindow(), QTStr("Updater.RepairConfirm.Title"),
+ QTStr("Updater.RepairConfirm.Text"),
+ QMessageBox::Yes | QMessageBox::Cancel);
+
+ return res == QMessageBox::Yes;
+}
+
+bool AutoUpdateThread::queryRepair()
+{
+ bool ret = false;
+ QMetaObject::invokeMethod(this, "queryRepairSlot",
+ Qt::BlockingQueuedConnection,
+ Q_RETURN_ARG(bool, ret));
+ return ret;
+}
+
void AutoUpdateThread::run()
try {
long responseCode;
@@ -615,11 +634,15 @@ try {
if (!success)
throw string("Failed to parse manifest");
- if (!updatesAvailable) {
+ if (!updatesAvailable && !repairMode) {
if (manualUpdate)
info(QTStr("Updater.NoUpdatesAvailable.Title"),
QTStr("Updater.NoUpdatesAvailable.Text"));
return;
+ } else if (updatesAvailable && repairMode) {
+ info(QTStr("Updater.RepairButUpdatesAvailable.Title"),
+ QTStr("Updater.RepairButUpdatesAvailable.Text"));
+ return;
}
/* ----------------------------------- *
@@ -627,7 +650,7 @@ try {
int skipUpdateVer = config_get_int(GetGlobalConfig(), "General",
"SkipUpdateVersion");
- if (!manualUpdate && updateVer == skipUpdateVer)
+ if (!manualUpdate && updateVer == skipUpdateVer && !repairMode)
return;
/* ----------------------------------- *
@@ -639,20 +662,25 @@ try {
/* ----------------------------------- *
* query user for update */
- int queryResult = queryUpdate(manualUpdate, notes.c_str());
+ if (repairMode) {
+ if (!queryRepair())
+ return;
+ } else {
+ int queryResult = queryUpdate(manualUpdate, notes.c_str());
- if (queryResult == OBSUpdate::No) {
- if (!manualUpdate) {
- long long t = (long long)time(nullptr);
+ if (queryResult == OBSUpdate::No) {
+ if (!manualUpdate) {
+ long long t = (long long)time(nullptr);
+ config_set_int(GetGlobalConfig(), "General",
+ "LastUpdateCheck", t);
+ }
+ return;
+
+ } else if (queryResult == OBSUpdate::Skip) {
config_set_int(GetGlobalConfig(), "General",
- "LastUpdateCheck", t);
+ "SkipUpdateVersion", updateVer);
+ return;
}
- return;
-
- } else if (queryResult == OBSUpdate::Skip) {
- config_set_int(GetGlobalConfig(), "General",
- "SkipUpdateVersion", updateVer);
- return;
}
/* ----------------------------------- *
diff --git a/UI/win-update/win-update.hpp b/UI/win-update/win-update.hpp
index 1e450a6ea..a9e944c59 100644
--- a/UI/win-update/win-update.hpp
+++ b/UI/win-update/win-update.hpp
@@ -7,19 +7,25 @@ class AutoUpdateThread : public QThread {
Q_OBJECT
bool manualUpdate;
+ bool repairMode;
bool user_confirmed = false;
virtual void run() override;
void info(const QString &title, const QString &text);
int queryUpdate(bool manualUpdate, const char *text_utf8);
+ bool queryRepair();
private slots:
void infoMsg(const QString &title, const QString &text);
int queryUpdateSlot(bool manualUpdate, const QString &text);
+ bool queryRepairSlot();
public:
- AutoUpdateThread(bool manualUpdate_) : manualUpdate(manualUpdate_) {}
+ AutoUpdateThread(bool manualUpdate_, bool repairMode_ = false)
+ : manualUpdate(manualUpdate_), repairMode(repairMode_)
+ {
+ }
};
class WhatsNewInfoThread : public QThread {
diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp
index b0bd1ea5b..ca01c7403 100644
--- a/UI/window-basic-main.cpp
+++ b/UI/window-basic-main.cpp
@@ -2025,9 +2025,11 @@ void OBSBasic::OBSInit()
delete ui->actionShowCrashLogs;
delete ui->actionUploadLastCrashLog;
delete ui->menuCrashLogs;
+ delete ui->actionRepair;
ui->actionShowCrashLogs = nullptr;
ui->actionUploadLastCrashLog = nullptr;
ui->menuCrashLogs = nullptr;
+ ui->actionRepair = nullptr;
#if !defined(__APPLE__)
delete ui->actionCheckForUpdates;
ui->actionCheckForUpdates = nullptr;
@@ -2041,8 +2043,12 @@ void OBSBasic::OBSInit()
#endif
#if defined(_WIN32) || defined(__APPLE__)
- if (App()->IsUpdaterDisabled())
+ if (App()->IsUpdaterDisabled()) {
ui->actionCheckForUpdates->setEnabled(false);
+#if defined(_WIN32)
+ ui->actionRepair->setEnabled(false);
+#endif
+ }
#endif
OnFirstLoad();
@@ -3666,6 +3672,7 @@ void OBSBasic::CheckForUpdates(bool manualUpdate)
trigger_sparkle_update();
#elif _WIN32
ui->actionCheckForUpdates->setEnabled(false);
+ ui->actionRepair->setEnabled(false);
if (updateCheckThread && updateCheckThread->isRunning())
return;
@@ -3680,6 +3687,7 @@ void OBSBasic::CheckForUpdates(bool manualUpdate)
void OBSBasic::updateCheckFinished()
{
ui->actionCheckForUpdates->setEnabled(true);
+ ui->actionRepair->setEnabled(true);
}
void OBSBasic::DuplicateSelectedScene()
@@ -6112,6 +6120,20 @@ void OBSBasic::on_actionCheckForUpdates_triggered()
CheckForUpdates(true);
}
+void OBSBasic::on_actionRepair_triggered()
+{
+#if defined(_WIN32)
+ ui->actionCheckForUpdates->setEnabled(false);
+ ui->actionRepair->setEnabled(false);
+
+ if (updateCheckThread && updateCheckThread->isRunning())
+ return;
+
+ updateCheckThread.reset(new AutoUpdateThread(false, true));
+ updateCheckThread->start();
+#endif
+}
+
void OBSBasic::logUploadFinished(const QString &text, const QString &error)
{
ui->menuLogFiles->setEnabled(true);
diff --git a/UI/window-basic-main.hpp b/UI/window-basic-main.hpp
index 0221bcab1..d16dad7cd 100644
--- a/UI/window-basic-main.hpp
+++ b/UI/window-basic-main.hpp
@@ -985,6 +985,7 @@ private slots:
void on_actionUploadLastLog_triggered();
void on_actionViewCurrentLog_triggered();
void on_actionCheckForUpdates_triggered();
+ void on_actionRepair_triggered();
void on_actionShowCrashLogs_triggered();
void on_actionUploadLastCrashLog_triggered();