stremio-community-v5/build/deploy_windows.js
Zarg 372301093f 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
2024-12-26 19:07:15 +01:00

246 lines
No EOL
9.2 KiB
JavaScript

#!/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);
}
}