Skip to content

feat: Check GitHub for a newer release at startup - #68

Merged
semnil merged 8 commits into
masterfrom
feat/update-check
Nov 1, 2026
Merged

semnil merged 8 commits into
masterfrom
feat/update-check

Conversation

@semnil

@semnil semnil commented Nov 1, 2026 •

Copy link
Copy Markdown
Owner

What

At startup the plugin checks GitHub for a newer release. When there is one, it asks before downloading it, checks the downloaded file against the SHA-256 that GitHub reports, and asks before starting the installer.

Behavior

  • When OBS finishes loading (OBS_FRONTEND_EVENT_FINISHED_LOADING), a worker thread requests https://api.github.com/repos/semnil/MixTrack2Source/releases/latest and compares its tag_name with the plugin version. Only the X.Y.Z form is compared, the form .github/scripts/release-tag-shape accepts for a release that is not a prerelease; releases/latest does not return prereleases.
  • For a newer release, the file for the platform is picked by the end of its name (-windows-x64-Installer.exe, -macos-universal.pkg, -x86_64-linux-gnu.deb, mirroring the names that Package-Windows.ps1, package-macos and CPACK_PACKAGE_FILE_NAME produce). It needs an https URL and a sha256: digest in the API response.
  • The plugin asks Mix Track to Source %1 is available. Download it? (Mix Track to Source %1 が公開されています。ダウンロードしますか?) with Download and Later.
  • Download saves the file through QSaveFile to the Downloads folder, or to the plugin's folder in the OBS settings folder (plugin_config/mix-track-to-source) when the Downloads folder does not exist. Both belong to the current user; a temporary folder that other users can write to (/tmp on Linux) is not used. The file is kept only when its SHA-256 matches the digest.
  • A file of the same name already there is used without downloading only when it is a regular file, not a symbolic link, with that SHA-256, and, outside Windows, owned by the current user.
  • After the download:
    • On Windows and macOS, the plugin asks whether to start the installer. Start Installer opens the file with QDesktopServices::openUrl.
    • On Linux, it shows where the package is saved and says to install it with sudo dpkg -i. Open Folder opens the folder.
  • Tools > Mix Track to Source: Check for Updates at Startup turns the check on or off. It is on until it is turned off; the choice is stored in plugin_config/mix-track-to-source/config.json.
  • Failures (network, HTTP status, digest mismatch, file errors) are logged and show no dialog. Log lines name the downloaded file, not its folder.
  • Unloading the plugin cancels a running request (through the libcurl progress callback) and joins the worker thread. Dialogs still queued for the UI thread are dropped with the receiver object that is deleted at unload.

Build

  • ENABLE_FRONTEND_API and ENABLE_QT are on in the template preset. The update check is compiled only when both are on (ENABLE_UPDATE_CHECK).
  • Requests use libcurl (CURL::libcurl), not Qt Network. With the Qt DLLs and plugin folder of OBS Studio 33.0.1 on Windows, Qt 6.11.1 has no TLS backend and an HTTPS request fails with TLS initialization failed. obs-deps has libcurl 8.12.1 for Windows, and OBS ships libcurl.dll.
  • Ubuntu CI installs libcurl4-openssl-dev.

Impact

  • The plugin now links obs-frontend-api, Qt Widgets and libcurl. On Windows, it imports KERNEL32.dll, MSVCP140.dll, Qt6Core.dll, Qt6Gui.dll, Qt6Widgets.dll, VCRUNTIME140.dll, VCRUNTIME140_1.dll, api-ms-win-crt-heap-l1-1-0.dll, api-ms-win-crt-runtime-l1-1-0.dll, api-ms-win-crt-stdio-l1-1-0.dll, libcurl.dll, obs-frontend-api.dll and obs.dll; the OBS and Qt ones are in OBS Studio 33.0.1's bin\64bit, and MSVCP140.dll is in System32.
  • While the check is on, every OBS start sends one unauthenticated request to api.github.com, whose limit for those is 60 per hour per IP address (X-RateLimit-Limit).
  • feat: Remove output tracks from sources feeding the input and add the source to every scene #63 looks up obs_frontend_add_event_callback at run time instead of linking obs-frontend-api; this change links it. Both add a call before obs_log(LOG_INFO, "plugin unloaded") in obs_module_unload, so git merge-tree --write-tree reports a conflict in src/plugin-main.c there; keeping both calls resolves it. fix: Keep the input track out of the plugin's outputs when they are set #66 merges without conflicts.
  • fix: Install the plugin in the OBS 33 plugin location #67 changes the install layout. The two branches merge without conflicts (git merge-tree --write-tree).

Verification

  • Windows build of this head: cmake --preset windows-x64 -DCMAKE_COMPILE_WARNING_AS_ERROR=ON, cmake --build and cmake --install pass. clang-format 19.1.1 (the version CI requires) reports no changes for src/plugin-main.c, src/update-check.cpp, src/update-check.h and src/update-version.hpp; gersemi 0.21.0 reports none for CMakeLists.txt.
  • A Qt program run with OBS Studio 33.0.1's Qt DLLs and plugin folder reports Qt 6.11.1, no TLS backend, supportsSsl 0 and TLS initialization failed for the request above. The same program with obs-deps' Qt 6.8.3 and its plugin folder reports cert-only,schannel and HTTP 200.
  • A program built with src/update-version.hpp passes its checks:
    • Versions: parsing and comparison (1.0.10 is newer than 1.0.9, 1.1.0 newer than 1.0.10), and rejecting v1.0.2, 1.0, 1.0.2.3, 1.0.2-rc1, a trailing newline, a leading space, an empty tag, an overflowing number and a negative one.
    • Assets: skipping one without a digest, with an http URL, with an uppercase digest and with a short digest.
    • Live response: the current releases/latest (1.0.2), from which it picks the Windows, macOS and Ubuntu files with their digests.
    • Download folder: an existing folder is kept; a missing folder, an empty path and a file path give the fallback.
    • Reuse: a regular file with the expected SHA-256 is reused; a file with another SHA-256, a folder, a missing file and an empty SHA-256 are not.
    • With the version pattern not anchored, v1.0.2, 1.0.2.3, 1.0.2-rc1, the trailing newline and the leading space are accepted, and those checks fail. Without the existence check, the missing folder and the file path keep the preferred path. Comparing only that the file can be read, the file with another SHA-256 and the empty SHA-256 are reused.
  • With OBS Studio 33.0.1's Qt DLLs, QSaveFile::open fails for a path whose parent folder does not exist (OpenError, 「指定されたパスが見つかりません。」), which is what the Downloads fallback avoids.
  • OBS Studio 33.0.1 on Windows, with a 1.0.1 build of this change (in a tree that also had fix: Install the plugin in the OBS 33 plugin location #67) loaded through OBS_PLUGINS_PATH:
    • the log shows plugin loaded successfully (version 1.0.1), update 1.0.2 is available, then, after Download, downloading update as mix-track-to-source-1.0.2-windows-x64-Installer.exe and downloaded update as mix-track-to-source-1.0.2-windows-x64-Installer.exe
    • the saved file is 2161556 bytes with SHA-256 d17801b540c76932963794ef7e3256e958a7565024bcd0401a49fc5b9d9121e5, the size and digest that the API reports for the release file
    • Start Installer started the installer, and the Tools menu showed the item checked
    • the build used in this run was made before two constants in src/update-check.cpp were renamed (CONNECT_TIMEOUT_SECONDS, LOW_SPEED_TIME_SECONDS), a comment in src/update-version.hpp was extended, and the fallback folder and reuse checks above were added
  • CI on 7565daf passes (Ubuntu, Windows and macOS builds and the format checks).
  • Ubuntu, checked after the merge on master at e95a844 (which contains this change) in Docker, with the obsproject PPA's OBS on ubuntu:24.04 (32.2.0) and ubuntu:26.04 (33.0.0): every OBS start under Xvfb logs [mix-track-to-source] no update (latest release 1.0.2), which check_for_update logs only after fetch has returned the latest release and its tag has been compared with the installed version.
  • On both, the logic test program and a Linux-only program built against src/update-version.hpp with Ubuntu's Qt 6 pass all their checks: a regular file of the current user with the expected SHA-256 is reused, while a symbolic link to such a file and a matching file owned by uid 65534 are not.
  • Not verified: the behavior on macOS; on Ubuntu, the download prompt, the download and the dialog after it (the installed version is the latest release, so only the no-update path ran).

🤖 Generated with Claude Code

semnil and others added 4 commits November 1, 2026 14:10
Add libcurl4-openssl-dev to the build dependencies that the Ubuntu
setup installs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Set ENABLE_FRONTEND_API and ENABLE_QT to true in the template preset
that every configure preset inherits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When OBS finishes loading, a worker thread asks the GitHub API for the
latest release and compares its X.Y.Z tag with the plugin version. For
a newer release that has a file for this platform with a sha256
digest, the plugin asks whether to download it. The file is saved to
the Downloads folder and kept only when its sha256 matches the digest;
a file already there with that sha256 is used as it is. Then, on
Windows and macOS, the plugin asks whether to start the installer, and
on Linux it shows where the package is and offers to open the folder.

The requests use libcurl, linked when ENABLE_FRONTEND_API and ENABLE_QT
are on, because the Qt that OBS Studio 33.0.1 ships on Windows has no
TLS backend. The Tools menu gets a checkable item that turns the check
at startup on or off; it is on until turned off, and the choice is
stored in the plugin's config.json. Unloading the plugin stops a
running request and waits for the worker thread.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add a section on the update check at startup, its Tools menu item, the
confirmation before the download, the sha256 check and the installer
prompt to the English and Japanese READMEs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@semnil
semnil force-pushed the feat/update-check branch from e93da25 to d6cccb2 Compare November 1, 2026 05:12
semnil and others added 4 commits November 1, 2026 14:12
QStandardPaths can return a Downloads folder that does not exist, and
QSaveFile does not create the folder, so the download stopped with a
log line. Use the temporary folder when the Downloads folder is not an
existing directory, and say so in the READMEs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The temporary folder that downloads fell back to is /tmp on Linux,
which other users can write to. Fall back to the plugin's folder in the
OBS settings folder instead, which belongs to the current user and is
created when it is missing, and say so in the READMEs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A file already at the download path was reused when its sha256
matched. Reuse it only when it is a regular file, not a symbolic link,
and, outside Windows, owned by the current user. The sha256 helper
moves to src/update-version.hpp with this check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Iterating a QJsonArray yields temporaries, and binding them to a
const QJsonValue reference is an error with clang under -Werror
(-Wrange-loop-bind-reference), which stopped the macOS build. Take
each value by value.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@semnil
semnil merged commit f28531c into master Nov 1, 2026
8 checks passed
@semnil
semnil deleted the feat/update-check branch November 1, 2026 05:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant