From 372301093f421bee4cc2051750fb123fb4e53e74 Mon Sep 17 00:00:00 2001 From: Zarg <62082797+Zaarrg@users.noreply.github.com> Date: Thu, 26 Dec 2024 19:07:15 +0100 Subject: [PATCH] Updated Windows deploy script + ubuntu updater fix - Using a node script instead for windows deployment - ( Will be later used for github automatic deployment) - Updated windows.md with updated deploy steps - Autoupdater fix for ubuntu causing update prompt to always show - Libmpv version bump for ubuntu support --- build/build_windows.bat | 155 ----------------------- build/deploy_windows.js | 246 ++++++++++++++++++++++++++++++++++++ deps/libmpv | 2 +- docs/WINDOWS.md | 25 +--- src/updater/autoupdater.cpp | 2 +- src/updater/autoupdater.h | 2 +- 6 files changed, 256 insertions(+), 176 deletions(-) delete mode 100644 build/build_windows.bat create mode 100644 build/deploy_windows.js diff --git a/build/build_windows.bat b/build/build_windows.bat deleted file mode 100644 index a0d188b..0000000 --- a/build/build_windows.bat +++ /dev/null @@ -1,155 +0,0 @@ -@echo off -REM ============================================ -REM Build and prepare the dist-win folder -REM ============================================ - -REM Check if BUILD_DIR is provided as an argument -if "%~1"=="" ( - REM Prompt the user for BUILD_DIR - set /p BUILD_DIR="Please enter the path to the build directory (e.g., C:\path\to\build): " -) else ( - set "BUILD_DIR=%~1" -) - -REM Check if SSL_BIN_DIR is provided as an argument -if "%~2"=="" ( - REM Prompt the user for SSL_BIN_DIR - set /p SSL_BIN_DIR="Please enter the path to the OpenSSL bin directory (e.g., C:\Program Files\OpenSSL-Win64\bin): " -) else ( - set "SSL_BIN_DIR=%~2" -) - -REM Remove trailing backslash from BUILD_DIR if present -if "%BUILD_DIR:~-1%"=="\" set "BUILD_DIR=%BUILD_DIR:~0,-1%" - - -REM Define variables -set "PROJECT_NAME=stremio" -pushd %~dp0.. -set "SOURCE_DIR=%CD%\" -popd -set "DIST_DIR=%SOURCE_DIR%dist\win" -set "BUILD_DIR=%SOURCE_DIR%%BUILD_DIR%" - -REM Define paths to MPV DLL and other dependencies -set "MPV_DLL=%SOURCE_DIR%deps\libmpv\x86_64\libmpv-2.dll" - -REM Step 0: Check if windeployqt.exe exists - -REM Check if windeployqt.exe exists in PATH -where windeployqt.exe >nul 2>&1 -if %ERRORLEVEL% EQU 0 ( - set "WINDEPLOYQT_EXECUTABLE=windeployqt.exe" - echo Found windeployqt.exe in PATH. -) else ( - echo windeployqt.exe not found in PATH. - REM Check if windeployqt.exe exists at the default path - set "DEFAULT_QT_BIN=C:\Qt\6.8.1\msvc2022_64\bin" - if exist "%DEFAULT_QT_BIN%\windeployqt.exe" ( - set "WINDEPLOYQT_EXECUTABLE=%DEFAULT_QT_BIN%\windeployqt.exe" - echo Found windeployqt.exe at default path: %WINDEPLOYQT_EXECUTABLE% - ) else ( - REM Prompt the user for the qt5\bin path - set /p QT_BIN_DIR="Please enter the path to qt5\bin directory (e.g., C:\Qt\5.15.2\msvc2019_64\bin): " - if exist "%QT_BIN_DIR%\windeployqt.exe" ( - set "WINDEPLOYQT_EXECUTABLE=%QT_BIN_DIR%\windeployqt.exe" - echo Found windeployqt.exe at: %WINDEPLOYQT_EXECUTABLE% - ) else ( - echo Error: windeployqt.exe not found at specified location. - pause - exit /b 1 - ) - ) -) - -REM Start the build process -echo ============================================ -echo Building and preparing the dist-win folder -echo ============================================ - -REM Step 1: Clean and create dist-win directory -echo Cleaning and creating dist-win directory... -if exist "%DIST_DIR%" ( - REM Remove read-only attributes - attrib -R "%DIST_DIR%" /S /D - REM Force delete directory - rmdir /S /Q "%DIST_DIR%" -) -mkdir "%DIST_DIR%" - -REM Step 2: Copy executable to dist-win -echo Copying executable to dist-win... -if exist "%BUILD_DIR%\%PROJECT_NAME%.exe" ( - copy "%BUILD_DIR%\%PROJECT_NAME%.exe" "%DIST_DIR%" /Y >nul -) else ( - echo Error: Executable %PROJECT_NAME%.exe not found in %BUILD_DIR%. - pause - exit /b 1 -) - -REM Verify that the executable exists in dist-win -if exist "%DIST_DIR%\%PROJECT_NAME%.exe" ( - echo Executable copied successfully. -) else ( - echo Error: Executable %PROJECT_NAME%.exe not found in %DIST_DIR%. - pause - exit /b 1 -) - -REM Step 3: Copy MPV DLL into dist-win -echo Copying MPV DLL into dist-win... -copy "%MPV_DLL%" "%DIST_DIR%" /Y >nul - -REM Step 4: Copy server.js into dist-win -echo Copying server.js into dist-win... -copy "%SOURCE_DIR%utils\windows\server.js" "%DIST_DIR%" /Y >nul - -REM Step 5: Copy node.exe into dist-win -echo Copying node.exe into dist-win... -copy "%SOURCE_DIR%utils\windows\node.exe" "%DIST_DIR%" /Y >nul - -REM Step 6: Copy required OpenSSL DLLs into dist-win -echo Copying required OpenSSL DLLs into dist-win... - -set DLL_LIST=libcrypto-3-x64.dll libssl-3-x64.dll - -for %%D in (%DLL_LIST%) do ( - echo Copying %%D... - copy "%SSL_BIN_DIR%\%%D" "%DIST_DIR%" /Y >nul - if ERRORLEVEL 1 ( - echo Failed to copy %%D. Aborting... - exit /b 1 - ) -) - -echo All DLLs copied successfully. - - -REM Step 7: Copy all files from windows\DS\ into dist-win -echo Copying DS files into dist-win... -xcopy "%SOURCE_DIR%utils\windows\DS\*" "%DIST_DIR%\" /E /I /Y >nul - -REM Step 7.1: Copy all files from windows\DS\ into dist-win -echo Copying stremio-runtime files into dist-win... -xcopy "%SOURCE_DIR%utils\windows\stremio-runtime.exe" "%DIST_DIR%\" /Y >nul - -REM Step 7.2: Copy all files from windows\ffmpeg\ into dist-win -echo Copying ffmpeg files into dist-win... -xcopy "%SOURCE_DIR%utils\windows\ffmpeg\*" "%DIST_DIR%\" /E /I /Y >nul - -REM Step 8: Run windeployqt in dist-win -echo Deploying Qt dependencies with windeployqt... -%WINDEPLOYQT_EXECUTABLE% --qmldir %SOURCE_DIR% %DIST_DIR%\%PROJECT_NAME%.exe - -REM Check if windeployqt succeeded -if %ERRORLEVEL% NEQ 0 ( - echo Error: windeployqt failed. - pause - exit /b 1 -) - -echo ============================================ -echo Build and preparation of dist-win completed. -echo ============================================ - -pause \ No newline at end of file diff --git a/build/deploy_windows.js b/build/deploy_windows.js new file mode 100644 index 0000000..f94e9e2 --- /dev/null +++ b/build/deploy_windows.js @@ -0,0 +1,246 @@ +#!/usr/bin/env node + +/**************************************************************************** + * deploy_windows.js + * + * Builds windows distributable folder dist/win. + * Pass --installer to also build the windows installer + * Make sure to have set up utils/windows and the environment correctly by following windows.md + * + ****************************************************************************/ + +const fs = require('fs'); +const path = require('path'); +const { execSync } = require('child_process'); +const readline = require('readline'); + +// --------------------------------------------------------------------- +// Project/Layout Configuration +// --------------------------------------------------------------------- +const SOURCE_DIR = path.resolve(__dirname, '..'); +const BUILD_DIR = path.join(SOURCE_DIR, 'cmake-build-release'); +const DIST_DIR = path.join(SOURCE_DIR, 'dist', 'win'); +const PROJECT_NAME = 'stremio'; + +// Paths to Additional Dependencies +const MPV_DLL = path.join(SOURCE_DIR, 'deps', 'libmpv', 'x86_64', 'libmpv-2.dll'); +const SERVER_JS = path.join(SOURCE_DIR, 'utils', 'windows', 'server.js'); +const NODE_EXE = path.join(SOURCE_DIR, 'utils', 'windows', 'node.exe'); +const DS_FOLDER = path.join(SOURCE_DIR, 'utils', 'windows', 'DS'); +const STREMIO_RUNTIME_EXE = path.join(SOURCE_DIR, 'utils', 'windows', 'stremio-runtime.exe'); +const FFMPEG_FOLDER = path.join(SOURCE_DIR, 'utils', 'windows', 'ffmpeg'); + +// Default Paths +const DEFAULT_OPENSSL_BIN = 'C:\\Program Files\\OpenSSL-Win64\\bin'; +const DEFAULT_QT_BIN = 'C:\\Qt\\6.8.1\\msvc2022_64\\bin'; +const DEFAULT_NSIS = 'C:\\Program Files (x86)\\NSIS\\makensis.exe'; + +// --------------------------------------------------------------------- +// Main +// --------------------------------------------------------------------- +(async function main() { + try { + const args = process.argv.slice(2); + const buildInstaller = args.includes('--installer'); + + // 1) Check or ask for OpenSSL path + let sslBinDir = DEFAULT_OPENSSL_BIN; + if (!fs.existsSync(sslBinDir)) { + console.log(`Default OpenSSL bin not found at: ${sslBinDir}`); + sslBinDir = await askQuestion( + 'Enter path to OpenSSL bin (e.g., C:\\Program Files\\OpenSSL-Win64\\bin): ' + ); + if (!fs.existsSync(sslBinDir)) { + console.error(`Error: No valid OpenSSL bin dir at: ${sslBinDir}`); + process.exit(1); + } + } + console.log(`Using OpenSSL bin: ${sslBinDir}\n`); + + // 2) Locate windeployqt.exe + let windeployqtPath = findInPath('windeployqt.exe'); + if (!windeployqtPath) { + const defaultWindeployqt = path.join(DEFAULT_QT_BIN, 'windeployqt.exe'); + if (fs.existsSync(defaultWindeployqt)) { + windeployqtPath = defaultWindeployqt; + console.log(`Found windeployqt.exe at default path: ${windeployqtPath}`); + } else { + const promptQtBin = await askQuestion( + 'Enter path to Qt bin (e.g. C:\\Qt\\6.8.1\\msvc2022_64\\bin): ' + ); + const possibleQtExe = path.join(promptQtBin, 'windeployqt.exe'); + if (!fs.existsSync(possibleQtExe)) { + console.error('Error: windeployqt.exe not found at that location.'); + process.exit(1); + } + windeployqtPath = possibleQtExe; + } + } else { + console.log(`Found windeployqt.exe in PATH: ${windeployqtPath}`); + } + + // 3) Run CMake + Ninja in ../cmake-build-release (64-bit) + if (!fs.existsSync(BUILD_DIR)) { + fs.mkdirSync(BUILD_DIR, { recursive: true }); + } + console.log('\n=== Running CMake in cmake-build-release ==='); + process.chdir(BUILD_DIR); + execSync(`cmake -G Ninja -DCMAKE_BUILD_TYPE=Release ..`, { stdio: 'inherit' }); + + console.log('=== Running Ninja in cmake-build-release ==='); + execSync('ninja', { stdio: 'inherit' }); + + // Return to script directory + process.chdir(__dirname); + + // 4) Prepare dist\win + console.log(`\n=== Cleaning and creating ${DIST_DIR} ===`); + safeRemove(DIST_DIR); + fs.mkdirSync(DIST_DIR, { recursive: true }); + + // 5) Copy main .exe + const builtExe = path.join(BUILD_DIR, `${PROJECT_NAME}.exe`); + const distExe = path.join(DIST_DIR, `${PROJECT_NAME}.exe`); + copyFile(builtExe, distExe); + + // 6) Copy mpv DLL, server.js, node.exe + copyFile(MPV_DLL, path.join(DIST_DIR, path.basename(MPV_DLL))); + copyFile(SERVER_JS, path.join(DIST_DIR, path.basename(SERVER_JS))); + copyFile(NODE_EXE, path.join(DIST_DIR, 'node.exe')); + + // 7) Copy OpenSSL DLLs + console.log('Copying OpenSSL DLLs...'); + const dllList = ['libcrypto-3-x64.dll', 'libssl-3-x64.dll']; + for (const dll of dllList) { + copyFile(path.join(sslBinDir, dll), path.join(DIST_DIR, dll)); + } + + // 8) Flatten DS folder, stremio-runtime, ffmpeg + console.log('Flattening DS folder, stremio-runtime, ffmpeg...'); + copyFolderContents(DS_FOLDER, DIST_DIR); + copyFile(STREMIO_RUNTIME_EXE, path.join(DIST_DIR, 'stremio-runtime.exe')); + copyFolderContents(FFMPEG_FOLDER, DIST_DIR); + + // 9) Run windeployqt.exe + console.log('\n=== Deploying Qt dependencies ==='); + execSync(`"${windeployqtPath}" --qmldir "${SOURCE_DIR}" "${distExe}"`, { stdio: 'inherit' }); + + console.log('\n=== dist\\win preparation complete. ==='); + + // 10) If --installer, parse version and build NSIS + if (buildInstaller) { + console.log('\n--installer detected: building NSIS installer...'); + // Extract the version first so we can set process.env before calling NSIS + const version = getPackageVersionFromCMake(); + process.env.package_version = version; + console.log(`Set package_version to: ${version}`); + buildNsisInstaller(); + } + + console.log('\nAll done!'); + } catch (err) { + console.error('Error in deploy_windows.js:', err); + process.exit(1); + } +})(); + +/**************************************************************************** + * Helper Functions + ****************************************************************************/ + +function askQuestion(prompt) { + const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); + return new Promise(resolve => { + rl.question(prompt, answer => { + rl.close(); + resolve(answer.trim()); + }); + }); +} + +function safeRemove(dirPath) { + if (fs.existsSync(dirPath)) { + fs.rmSync(dirPath, { recursive: true, force: true }); + } +} + +function copyFile(src, dest) { + if (!fs.existsSync(src)) { + console.warn(`Warning: missing file: ${src}`); + return; + } + fs.copyFileSync(src, dest); + console.log(`Copied: ${src} -> ${dest}`); +} + +/** + * Recursively copies only the contents of "src" into "dest" (flattened). + * If src has files/folders, they go directly into dest, rather than + * creating a subfolder named src. + */ +function copyFolderContents(src, dest) { + if (!fs.existsSync(src)) { + console.warn(`Warning: missing folder: ${src}`); + return; + } + const stats = fs.statSync(src); + if (!stats.isDirectory()) { + console.warn(`Warning: not a directory: ${src}`); + return; + } + for (const item of fs.readdirSync(src)) { + const srcItem = path.join(src, item); + const itemStats = fs.statSync(srcItem); + const destItem = path.join(dest, item); + if (itemStats.isDirectory()) { + copyFolderContents(srcItem, dest); + } else { + copyFile(srcItem, destItem); + } + } +} + +/** + * Attempt to find an executable in PATH on Windows. + */ +function findInPath(executable) { + try { + const result = execSync(`where ${executable}`, { stdio: ['pipe', 'pipe', 'ignore'] }); + return result.toString().split(/\r?\n/)[0].trim(); + } catch { + return null; + } +} + +/** + * Retrieves version from CMakeLists.txt (handles quotes): + * project(stremio VERSION "5.0.2") + */ +function getPackageVersionFromCMake() { + const cmakeFile = path.join(SOURCE_DIR, 'CMakeLists.txt'); + let version = '0.0.0'; + if (fs.existsSync(cmakeFile)) { + const content = fs.readFileSync(cmakeFile, 'utf8'); + // Accept either quoted or unquoted numerical version + const match = content.match(/project\s*\(\s*stremio\s+VERSION\s+"?([\d.]+)"?\)/i); + if (match) { + version = match[1]; + } + } + return version; +} + +function buildNsisInstaller() { + if (!fs.existsSync(DEFAULT_NSIS)) { + console.warn(`NSIS not found at default path: ${DEFAULT_NSIS}. Skipping installer.`); + return; + } + try { + const nsiScript = path.join(SOURCE_DIR, 'utils', 'windows', 'installer', 'windows-installer.nsi'); + console.log(`Running makensis.exe with version: ${process.env.package_version} ...`); + execSync(`"${DEFAULT_NSIS}" "${nsiScript}"`, { stdio: 'inherit' }); + console.log(`\nInstaller created: "Stremio ${process.env.package_version}.exe"`); + } catch (err) { + console.error('Failed to run NSIS (makensis.exe):', err); + } +} \ No newline at end of file diff --git a/deps/libmpv b/deps/libmpv index 145b8ac..d57999b 160000 --- a/deps/libmpv +++ b/deps/libmpv @@ -1 +1 @@ -Subproject commit 145b8ac1ec57dd5e93993670d53b06e0a7e2c486 +Subproject commit d57999b78b2d7b22f32f3a827a44903fdaa59e62 diff --git a/docs/WINDOWS.md b/docs/WINDOWS.md index 0d677b6..c3dcb70 100644 --- a/docs/WINDOWS.md +++ b/docs/WINDOWS.md @@ -80,30 +80,19 @@ Ensure the following are installed on your system: ``` --- -### 5️⃣ **Build the Shell** +### 5️⃣ **Build / Deploying the Shell** -1. Make sure to run the following in the `Developer Command Prompt for VS 2022` +1. Make sure to run the following in the `x64 Native Tools Command Prompt for VS 2022` -> **⏳ Note:** Make sure to set the Envs from step 4.2 - -2. Generate the build files: +2. Run the deployment script in the ``build`` folder ```cmd - cmake -G"NMake Makefiles" -DCMAKE_BUILD_TYPE=Release .. - ``` -3. Compile: - ```cmd - cmake --build . + node deploy_windows.js --installer ``` +> **⏳ Note:** This script uses common paths for ``qt`` and ``openssl`` make sure those are installed. If running with ``--installer`` make sure u installed ``nsis`` with the needed ``nsprocess`` plugin at least once. -4. Build distributable - ```cmd - build_windows.bat {cmake-build-folder} {openssl-bin} - - build_windows.bat cmake-build-release "C:\Program Files\OpenSSL-Win64\bin" - ``` +3. Done. This will build the `installer` and ``dist/win`` folder. - -> **⏳ Note:** This will create `dist-win` with all necessary files like `node.exe`, `ffmpeg.exe`. Also make sure to have `node.exe, stremio-runtime.exe, server.js` are in `utils\windows\` folder +> **⏳ Note:** This will create `dist/win` with all necessary files like `node.exe`, `ffmpeg.exe`. Also make sure to have `node.exe, stremio-runtime.exe, server.js` are in `utils\windows\` folder --- ## 📦 Installer (Optional) diff --git a/src/updater/autoupdater.cpp b/src/updater/autoupdater.cpp index 1702958..17fe808 100644 --- a/src/updater/autoupdater.cpp +++ b/src/updater/autoupdater.cpp @@ -218,7 +218,7 @@ void AutoUpdater::prepareUpdate(QJsonDocument versionDescDoc) { || versionDesc.value("shellVersion").toString() != QCoreApplication::applicationVersion() ) { toDownload = FULL_UPDATE_FILES; - } else if (files.value(PARTIAL_UPDATE_FILES).toObject().value("checksum").toString() != serverHashHex) { + } else if (files.value(SERVER_FNAME).toObject().value("checksum").toString() != serverHashHex) { toDownload = PARTIAL_UPDATE_FILES; } else { qDebug() << "Everything is up to date"; diff --git a/src/updater/autoupdater.h b/src/updater/autoupdater.h index 5fadffb..824a041 100644 --- a/src/updater/autoupdater.h +++ b/src/updater/autoupdater.h @@ -30,7 +30,7 @@ extern "C" { #define SERVER_FNAME "server.js" //#define ASAR_FNAME "stremio.asar" -#define PARTIAL_UPDATE_FILES { SERVER_FNAME, "" } +#define PARTIAL_UPDATE_FILES { SERVER_FNAME } #if defined(Q_OS_WIN) #define FULL_UPDATE_FILES { "windows" }