diff --git a/download-via-browser.js b/download-via-browser.js new file mode 100644 index 0000000..1b1b999 --- /dev/null +++ b/download-via-browser.js @@ -0,0 +1,65 @@ +#!/usr/bin/env node + +const { chromium } = require("playwright"); + +const targetUrl = process.argv[2]; +const savePath = process.argv[3]; + +if (!targetUrl || !savePath) { + process.exit(1); +} + +(async () => { + let browser = null; + + try { + browser = await chromium.launch({ + headless: true, + executablePath: "/usr/bin/chromium-headless-shell", + args: [ + "--no-sandbox", + "--disable-setuid-sandbox", + "--disable-gpu", + "--disable-dev-shm-usage", + "--disable-blink-features=AutomationControlled", + ], + }); + + const context = await browser.newContext({ + // 实测不需要 + // userAgent: 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36', + }); + + // 参考文档 + // https://playwright.dev/docs/downloads + // https://playwright.dev/docs/api/class-download + + const page = await context.newPage(); + const downloadPromise = page.waitForEvent("download", { + timeout: 60000, + }); + + await page.goto(targetUrl, { waitUntil: "commit" }).catch((e) => { + // 下载直链会触发 'Download is starting' 异常,要手动忽略 + // https://github.com/microsoft/playwright/blob/v1.60.0/tests/library/download.spec.ts#L68 + if (!e.message.includes("Download is starting")) { + throw e; + } + }); + console.error("Page opened:", targetUrl); + + const download = await downloadPromise; + const suggestedFilename = download.suggestedFilename(); + console.error("Download started:", suggestedFilename, savePath); + + await download.saveAs(savePath); + console.error("Download completed:", suggestedFilename, savePath); + } catch (err) { + console.error("Download failed:", err); + process.exitCode = 1; + } finally { + if (browser) { + await browser.close(); + } + } +})(); diff --git a/trans.sh b/trans.sh index f6b0460..e270dc3 100644 --- a/trans.sh +++ b/trans.sh @@ -195,6 +195,57 @@ is_magnet_link() { [[ "$1" = magnet:* ]] } +create_alpine_rootfs() { + local os_dir=$1 + local init_now=${2:-false} + + # 复制当前系统的 /etc/apk 文件夹 + mkdir -p "$os_dir" + cp -a --parents /etc/apk "$os_dir" + rm -f "$os_dir/etc/apk/world" + + # 安装 alpine + apk add --root "$os_dir" --initdb \ + alpine-base openssl ca-certificates + + if $init_now; then + cp_resolv_conf "$os_dir" + mount_pseudo_fs "$os_dir" + fi +} + +download_via_browser() { + local url=$1 + local path=$2 + + local os_dir=/os/alpine_for_browser + mkdir_clear "$os_dir" + + # 安装 chromium-headless-shell npm 到硬盘,减少内存占用 + create_alpine_rootfs "$os_dir" true + apk add --root "$os_dir" chromium-headless-shell npm + + # 安装 playwright + # shellcheck disable=SC2046 + PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 \ + chroot "$os_dir" \ + npm install \ + --no-save --no-package-lock \ + --prefix "/work" \ + $(is_in_china && echo '--registry=https://registry.npmmirror.com') \ + playwright + + # 下载文件 + # shellcheck disable=SC2154 + wget "$confhome/download-via-browser.js" -O "$os_dir/work/download-via-browser.js" + retry 5 chroot "$os_dir" node /work/download-via-browser.js "$url" "/work/download_file" + cp "$os_dir/work/download_file" "$path" + + # 清理 + umount_pseudo_fs "$os_dir" + rm -rf "$os_dir" +} + download() { local url=$1 local path=$2 @@ -6873,7 +6924,8 @@ install_windows() { ) # 注意 intel 禁止了 aria2 下载 - download "$url" $drv/intel.zip true + # 还使用了 aws waf,要用浏览器通过 js 获取 aws-waf-token cookie 才能下载 + download_via_browser "$url" $drv/intel.zip # inf 可能是 UTF-16 LE?因此用 rg 搜索 # 用 busybox unzip 解压 win10 驱动时,路径和文件名会粘在一起 @@ -7606,7 +7658,7 @@ EOF url=$(get_intel_download_url "$id" "SetupRST\.exe") # 注意 intel 禁止了 aria2 下载 - download $url $drv/SetupRST.exe true + download_via_browser $url $drv/SetupRST.exe apk add 7zip 7z x $drv/SetupRST.exe -o$drv/SetupRST -i!.text 7z x $drv/SetupRST/.text -o$drv/vmd