Add a windows11 target that downloads the Windows 11 ISO with headless Chromium

Move the Node.js script and its dependencies into nodejs/ and let
download-images.sh call it for the image architecture.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
GuofangandClaude Sonnet 5.5 committed 2026-10-21 16:45:36 +08:00
1 parent 5e58722aca
commit 592c7294c3
6 files changed
+228 -3

No files matched your search

+112
View File
@@ -0,0 +1,112 @@
#!/usr/bin/env node
// Print a signed, temporary download URL for the Windows 11 ISO by driving
// Microsoft's download page with headless Chromium.
//
// Usage: node get-windows-iso-url.js [--arch x64|arm64] [--lang NAME]
// Environment:
// PLAYWRIGHT_CORE playwright-core directory (default: node_modules here)
// CHROME_PATH Chromium executable (default: newest one in ~/.cache/ms-playwright)
// The URL expires after about 24 hours and may be bound to the IP that
// requested it. Only the URL goes to stdout; logs go to stderr.
const fs = require('fs');
const os = require('os');
const path = require('path');
const args = process.argv.slice(2);
if (args.includes('--help') || args.includes('-h')) {
console.log(`Usage: node get-windows-iso-url.js [options]
Print a signed, temporary download URL for the Windows 11 ISO (only the URL
goes to stdout; logs go to stderr).
Options:
--arch <x64|arm64> Architecture, default: the host's (x64 on amd64 hosts)
--lang <name> Language, default "English (United States)",
for example "Chinese Simplified"
-h, --help Show this help
Environment:
PLAYWRIGHT_CORE playwright-core directory (default: node_modules here)
CHROME_PATH Chromium executable (default: newest one in
~/.cache/ms-playwright)
Examples:
node get-windows-iso-url.js --arch x64 --lang "Chinese Simplified"
wget -c "$(node get-windows-iso-url.js 2>/dev/null)"
The URL expires after about 24 hours and may be bound to the IP that
requested it.`);
process.exit(0);
}
const opt = (name, def) => {
const i = args.indexOf(name);
return i < 0 ? def : (args[i + 1] && !args[i + 1].startsWith('--') ? args[i + 1] : true);
};
const hostArch = { x64: 'x64', arm64: 'arm64' }[process.arch];
const arch = opt('--arch', hostArch);
const lang = opt('--lang', 'English (United States)');
const pages = { arm64: 'windows11arm64', x64: 'windows11' };
if (!pages[arch]) {
console.error(arch === undefined ? `unsupported host architecture ${process.arch}: pass --arch x64|arm64` : '--arch must be x64 or arm64');
process.exit(2);
}
const log = (...a) => console.error('[iso]', ...a);
function findPlaywright() {
if (process.env.PLAYWRIGHT_CORE) return process.env.PLAYWRIGHT_CORE;
try { return path.dirname(require.resolve('playwright-core/package.json')); } catch {}
console.error('playwright-core not found: run npm ci or set PLAYWRIGHT_CORE');
process.exit(2);
}
function findChrome() {
if (process.env.CHROME_PATH) return process.env.CHROME_PATH;
const root = path.join(os.homedir(), '.cache/ms-playwright');
const dirs = fs.existsSync(root) ? fs.readdirSync(root).filter(d => /^chromium-\d+$/.test(d)).sort() : [];
if (!dirs.length) { console.error('Chromium not found: set CHROME_PATH or run npx playwright-core install chromium'); process.exit(2); }
return path.join(root, dirs.pop(), 'chrome-linux64/chrome');
}
(async () => {
const { chromium } = require(findPlaywright());
const browser = await chromium.launch({ executablePath: findChrome(), headless: true });
try {
const ctx = await browser.newContext({
locale: 'en-US',
userAgent: 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0 Safari/537.36',
});
const page = await ctx.newPage();
let api = null;
page.on('response', async r => {
if (/GetProductDownloadLinks/i.test(r.url())) api = await r.json().catch(() => null);
});
log('opening', pages[arch]);
await page.goto(`https://www.microsoft.com/en-us/software-download/${pages[arch]}`, { waitUntil: 'networkidle', timeout: 60000 });
await page.click('button:has-text("Accept")', { timeout: 3000 }).catch(() => {});
// Pick the first real edition (currently the only multi-edition ISO).
const edition = await page.$$eval('#product-edition option', o => o.map(x => x.value).find(v => v && v !== 'null'));
if (!edition) throw new Error('no edition option found; the page layout may have changed');
await page.selectOption('#product-edition', edition);
await page.click('#submit-product-edition');
await page.waitForSelector('#product-languages option:not([value="null"])', { state: 'attached', timeout: 60000 });
const langs = await page.$$eval('#product-languages option', o => o.map(x => ({ value: x.value, text: x.text })));
const hit = langs.find(l => l.text === lang);
if (!hit) throw new Error(`no language "${lang}"; available: ${langs.map(l => l.text).filter(t => t !== 'Choose one').join(', ')}`);
await page.selectOption('#product-languages', hit.value);
await page.click('#submit-sku');
await page.waitForSelector('a[href*="prss.microsoft.com"]', { timeout: 60000 });
const url = await page.$eval('a[href*="prss.microsoft.com"]', a => a.href);
const opts = api && api.ProductDownloadOptions;
log(opts ? opts[0].Name : '(API response not captured)', '| expires:', api && api.DownloadExpirationDatetime);
console.log(url);
} finally {
await browser.close();
}
})().catch(e => { console.error('[iso] failed:', e.message); process.exit(1); });
+28
View File
@@ -0,0 +1,28 @@
{
"name": "win-iso",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "win-iso",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"playwright-core": "^1.64.1"
}
},
"node_modules/playwright-core": {
"version": "1.64.1",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.64.1.tgz",
"integrity": "sha512-BC4s8y6SEVA6Q1rSxZTto8hI1KUI3xXlHGZgvGqP4IqPdI/a6FX9H29IDNz7vKo9l21b6LfYosScPL6M3xxyDQ==",
"license": "Apache-2.0",
"bin": {
"playwright-core": "cli.js"
},
"engines": {
"node": ">=20"
}
}
}
}
+16
View File
@@ -0,0 +1,16 @@
{
"name": "win-iso",
"version": "1.0.0",
"description": "",
"main": "get-windows-iso-url.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "commonjs",
"dependencies": {
"playwright-core": "^1.64.1"
}
}