discstation 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +137 -0
- package/arduino/c6/DiscStation_C6.ino +914 -0
- package/arduino/v1/DiscStation.ino +957 -0
- package/discstation.env.example +19 -0
- package/docs/PLATFORM_SUPPORT.md +39 -0
- package/install-macos.sh +80 -0
- package/install-windows.ps1 +24 -0
- package/install.sh +56 -0
- package/package.json +48 -0
- package/requirements.txt +20 -0
- package/scripts/setup.mjs +78 -0
- package/src/discstation.py +3984 -0
- package/src/discstation_burn.py +1697 -0
- package/src/discstation_host.py +380 -0
- package/src/discstation_meta.py +150 -0
- package/src/static/app.js +268 -0
- package/src/static/index.html +111 -0
- package/src/static/style.css +328 -0
- package/systemd/discstation.service +13 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Optional YouTube access settings. Copy to ~/.local/share/discstation/discstation.env.
|
|
2
|
+
# Do not commit cookies, user-agent values, or PO tokens.
|
|
3
|
+
YTDLP_PLAYER_CLIENTS=web_embedded,android_vr
|
|
4
|
+
YTDLP_HTTP_CHUNK_SIZE=1M
|
|
5
|
+
YTDLP_RETRIES=3
|
|
6
|
+
YTDLP_FRAGMENT_RETRIES=3
|
|
7
|
+
DISC_OUTPUT_LIMIT_BYTES=4300000000
|
|
8
|
+
DISC_DL_OUTPUT_LIMIT_BYTES=8000000000
|
|
9
|
+
|
|
10
|
+
# TMDb API key for video (DVD / burned movie) metadata lookup. Get a free key at
|
|
11
|
+
# https://www.themoviedb.org/settings/api . Without it, ripped videos keep their
|
|
12
|
+
# disc-label / filename naming. Alternatively put the key in
|
|
13
|
+
# ~/.local/share/discstation/tmdb.key
|
|
14
|
+
# DISCSTATION_TMDB_API_KEY=
|
|
15
|
+
# YTDLP_COOKIES_FROM_BROWSER=firefox
|
|
16
|
+
# YTDLP_COOKIES=/home/phuju/.config/discstation/youtube-cookies.txt
|
|
17
|
+
# YTDLP_USER_AGENT=Mozilla/5.0 ...
|
|
18
|
+
# YTDLP_PO_TOKEN=web_embedded.gvs+TOKEN
|
|
19
|
+
# YTDLP_EXTRACTOR_ARGS=youtube:player_client=web_embedded
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# DiscStation Platform Support
|
|
2
|
+
|
|
3
|
+
## Linux
|
|
4
|
+
|
|
5
|
+
Full host support: DVD-Video, data discs, ISO images, audio CDs, ripping,
|
|
6
|
+
playback, HTTPS web UI, ESP32 serial, and ESP32 Wi-Fi/OTA.
|
|
7
|
+
|
|
8
|
+
Run `./install.sh` on Debian, Ubuntu, or Raspberry Pi OS.
|
|
9
|
+
|
|
10
|
+
## macOS
|
|
11
|
+
|
|
12
|
+
The Python host and web/control workflow run with Homebrew dependencies. Data
|
|
13
|
+
and DVD image burning use `hdiutil`; DVD-Video discs can be mounted read-only
|
|
14
|
+
for playback and VIDEO_TS ripping; audio CD burning uses cdrdao. Optical-device
|
|
15
|
+
discovery and video/audio workflows are experimental; use `DISC_DEVICE`
|
|
16
|
+
when automatic detection does not find the external drive. Apple Music owns
|
|
17
|
+
audio CD playback and ripping on macOS, so DiscStation does not probe or access
|
|
18
|
+
audio tracks for those operations. Audio burns include CD-TEXT from the source
|
|
19
|
+
folder/file name and track metadata. Apple Music may still show generic track
|
|
20
|
+
names when its online CD lookup has no match; CD-TEXT-capable players can read
|
|
21
|
+
the embedded names. The macOS installer installs a persistent `launchd` service.
|
|
22
|
+
|
|
23
|
+
## Windows
|
|
24
|
+
|
|
25
|
+
The Python host and web/control workflow can run from PowerShell. Optical
|
|
26
|
+
burning needs a Windows IMAPI backend or a separately installed compatible
|
|
27
|
+
burning tool. The Windows installer deliberately reports this limitation
|
|
28
|
+
instead of silently attempting Linux commands.
|
|
29
|
+
|
|
30
|
+
## Shared Components
|
|
31
|
+
|
|
32
|
+
- DiscStation workflows and web UI
|
|
33
|
+
- ESP32 serial protocol
|
|
34
|
+
- File upload and folder preservation
|
|
35
|
+
- Video/audio metadata handling
|
|
36
|
+
- QR-code web URL display
|
|
37
|
+
|
|
38
|
+
The optical-drive backend is the platform boundary. It should be completed per
|
|
39
|
+
OS before claiming full native burning support on that platform.
|
package/install-macos.sh
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
ROOT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
|
|
5
|
+
APP_DIR="${DISCSTATION_APP_DIR:-$HOME/Library/Application Support/DiscStation/app}"
|
|
6
|
+
VENV_DIR="${DISCSTATION_VENV_DIR:-$HOME/Library/Application Support/DiscStation/venv}"
|
|
7
|
+
CONFIG_DIR="${DISCSTATION_CONFIG_DIR:-$HOME/Library/Application Support/DiscStation}"
|
|
8
|
+
PLIST="$HOME/Library/LaunchAgents/com.discstation.agent.plist"
|
|
9
|
+
|
|
10
|
+
if [[ "$(uname -s)" != "Darwin" ]]; then
|
|
11
|
+
printf 'Run this script on macOS.\n' >&2
|
|
12
|
+
exit 1
|
|
13
|
+
fi
|
|
14
|
+
if ! command -v brew >/dev/null 2>&1; then
|
|
15
|
+
printf 'Homebrew is missing. Starting the official Homebrew installer...\n'
|
|
16
|
+
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
if [[ -x /opt/homebrew/bin/brew ]]; then
|
|
20
|
+
eval "$(/opt/homebrew/bin/brew shellenv)"
|
|
21
|
+
elif [[ -x /usr/local/bin/brew ]]; then
|
|
22
|
+
eval "$(/usr/local/bin/brew shellenv)"
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
if ! command -v brew >/dev/null 2>&1; then
|
|
26
|
+
printf 'Homebrew installation did not complete.\n' >&2
|
|
27
|
+
exit 1
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
brew install python ffmpeg cdrdao dvdauthor node yt-dlp xorriso mpv libdiscid handbrake
|
|
31
|
+
mkdir -p "$APP_DIR" "$VENV_DIR" "$CONFIG_DIR"
|
|
32
|
+
cp -R "$ROOT_DIR/src/." "$APP_DIR/"
|
|
33
|
+
python3 -m venv "$VENV_DIR"
|
|
34
|
+
"$VENV_DIR/bin/python" -m pip install --upgrade pip
|
|
35
|
+
if [[ -f "$ROOT_DIR/requirements.txt" ]]; then
|
|
36
|
+
"$VENV_DIR/bin/python" -m pip install -r "$ROOT_DIR/requirements.txt"
|
|
37
|
+
else
|
|
38
|
+
"$VENV_DIR/bin/python" -m pip install pyserial mutagen requests yt-dlp
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
DISC_DEVICE="${DISC_DEVICE:-}"
|
|
42
|
+
DISC_PORT="${DISC_PORT:-$(ls /dev/cu.usbserial-* /dev/cu.usbmodem-* 2>/dev/null | head -1)}"
|
|
43
|
+
|
|
44
|
+
if [[ ! -f "$CONFIG_DIR/server.crt" || ! -f "$CONFIG_DIR/server.key" ]]; then
|
|
45
|
+
openssl req -x509 -newkey rsa:2048 -nodes -days 3650 \
|
|
46
|
+
-keyout "$CONFIG_DIR/server.key" \
|
|
47
|
+
-out "$CONFIG_DIR/server.crt" \
|
|
48
|
+
-subj "/CN=DiscStation"
|
|
49
|
+
chmod 600 "$CONFIG_DIR/server.key"
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
mkdir -p "$HOME/Library/LaunchAgents" "$HOME/Library/Logs"
|
|
53
|
+
cat > "$PLIST" <<PLIST
|
|
54
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
55
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
56
|
+
<plist version="1.0"><dict>
|
|
57
|
+
<key>Label</key><string>com.discstation.agent</string>
|
|
58
|
+
<key>ProgramArguments</key><array>
|
|
59
|
+
<string>$VENV_DIR/bin/python</string>
|
|
60
|
+
<string>$APP_DIR/discstation.py</string>
|
|
61
|
+
<string>--port</string><string>8080</string>
|
|
62
|
+
</array>
|
|
63
|
+
<key>EnvironmentVariables</key><dict>
|
|
64
|
+
<key>PATH</key><string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string>
|
|
65
|
+
<key>DISC_DEVICE</key><string>${DISC_DEVICE:-}</string>
|
|
66
|
+
<key>DISC_PORT</key><string>${DISC_PORT:-}</string>
|
|
67
|
+
</dict>
|
|
68
|
+
<key>WorkingDirectory</key><string>$APP_DIR</string>
|
|
69
|
+
<key>RunAtLoad</key><true/>
|
|
70
|
+
<key>KeepAlive</key><true/>
|
|
71
|
+
<key>StandardOutPath</key><string>$HOME/Library/Logs/DiscStation.log</string>
|
|
72
|
+
<key>StandardErrorPath</key><string>$HOME/Library/Logs/DiscStation.log</string>
|
|
73
|
+
</dict></plist>
|
|
74
|
+
PLIST
|
|
75
|
+
launchctl bootout "gui/$(id -u)" "$PLIST" 2>/dev/null || true
|
|
76
|
+
launchctl bootstrap "gui/$(id -u)" "$PLIST"
|
|
77
|
+
|
|
78
|
+
printf '\nDiscStation macOS host files installed at:\n%s\n' "$APP_DIR"
|
|
79
|
+
printf 'Optical-device support is experimental; set DISC_DEVICE if automatic detection fails.\n'
|
|
80
|
+
printf 'Run: %q %q\n' "$VENV_DIR/bin/python" "$APP_DIR/discstation.py"
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
$ErrorActionPreference = "Stop"
|
|
2
|
+
|
|
3
|
+
$Root = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
4
|
+
$App = if ($env:DISCSTATION_APP_DIR) { $env:DISCSTATION_APP_DIR } else { Join-Path $env:LOCALAPPDATA "DiscStation\app" }
|
|
5
|
+
$Venv = if ($env:DISCSTATION_VENV_DIR) { $env:DISCSTATION_VENV_DIR } else { Join-Path $env:LOCALAPPDATA "DiscStation\venv" }
|
|
6
|
+
|
|
7
|
+
if (-not (Get-Command py -ErrorAction SilentlyContinue)) {
|
|
8
|
+
throw "Install Python 3 from https://www.python.org/downloads/windows/ first."
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
New-Item -ItemType Directory -Force -Path $App, $Venv | Out-Null
|
|
12
|
+
Copy-Item -Recurse -Force (Join-Path $Root "src\*") $App
|
|
13
|
+
py -3 -m venv $Venv
|
|
14
|
+
& (Join-Path $Venv "Scripts\python.exe") -m pip install --upgrade pip
|
|
15
|
+
$Req = Join-Path $Root "requirements.txt"
|
|
16
|
+
if (Test-Path $Req) {
|
|
17
|
+
& (Join-Path $Venv "Scripts\python.exe") -m pip install -r $Req
|
|
18
|
+
} else {
|
|
19
|
+
& (Join-Path $Venv "Scripts\python.exe") -m pip install pyserial mutagen requests yt-dlp
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
Write-Host "DiscStation host files installed at $App"
|
|
23
|
+
Write-Host "The web/control workflow is available; optical burning requires a Windows IMAPI backend or compatible burning tools."
|
|
24
|
+
Write-Host "Run: $Venv\Scripts\python.exe $App\discstation.py"
|
package/install.sh
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
ROOT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
|
|
5
|
+
APP_DIR="${DISCSTATION_APP_DIR:-$HOME/.local/share/discstation/app}"
|
|
6
|
+
VENV_DIR="${DISCSTATION_VENV_DIR:-$HOME/.local/share/discstation/venv}"
|
|
7
|
+
CONFIG_DIR="${DISCSTATION_CONFIG_DIR:-$HOME/.local/share/discstation}"
|
|
8
|
+
|
|
9
|
+
if [[ "$(uname -s)" != "Linux" ]]; then
|
|
10
|
+
printf 'This installer is for Linux. Use install-macos.sh or install-windows.ps1.\n' >&2
|
|
11
|
+
exit 1
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
if command -v apt-get >/dev/null 2>&1; then
|
|
15
|
+
sudo apt-get update
|
|
16
|
+
sudo apt-get install -y \
|
|
17
|
+
cdrdao dvdauthor ffmpeg genisoimage growisofs handbrake-cli lsdvd mpv \
|
|
18
|
+
nodejs openssl python3 python3-pip python3-serial python3-mutagen \
|
|
19
|
+
python3-requests python3-pyudev python3-libdiscid python3-musicbrainzngs \
|
|
20
|
+
libdiscid0 python3-venv wodim
|
|
21
|
+
else
|
|
22
|
+
printf 'Unsupported Linux package manager. Install the DiscStation dependencies manually.\n' >&2
|
|
23
|
+
exit 1
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
mkdir -p "$APP_DIR" "$CONFIG_DIR" "$VENV_DIR"
|
|
27
|
+
cp -R "$ROOT_DIR/src/." "$APP_DIR/"
|
|
28
|
+
if [[ ! -f "$CONFIG_DIR/discstation.env" && -f "$ROOT_DIR/discstation.env.example" ]]; then
|
|
29
|
+
cp "$ROOT_DIR/discstation.env.example" "$CONFIG_DIR/discstation.env"
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
python3 -m venv --system-site-packages "$VENV_DIR"
|
|
33
|
+
"$VENV_DIR/bin/python" -m pip install --upgrade pip
|
|
34
|
+
if [[ -f "$ROOT_DIR/requirements.txt" ]]; then
|
|
35
|
+
"$VENV_DIR/bin/python" -m pip install -r "$ROOT_DIR/requirements.txt"
|
|
36
|
+
else
|
|
37
|
+
"$VENV_DIR/bin/python" -m pip install pyserial mutagen requests yt-dlp
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
if [[ ! -f "$CONFIG_DIR/server.crt" || ! -f "$CONFIG_DIR/server.key" ]]; then
|
|
41
|
+
openssl req -x509 -newkey rsa:2048 -nodes -days 3650 \
|
|
42
|
+
-keyout "$CONFIG_DIR/server.key" \
|
|
43
|
+
-out "$CONFIG_DIR/server.crt" \
|
|
44
|
+
-subj "/CN=DiscStation"
|
|
45
|
+
chmod 600 "$CONFIG_DIR/server.key"
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
sudo usermod -aG dialout,cdrom "$USER" || true
|
|
49
|
+
mkdir -p "$HOME/.config/systemd/user"
|
|
50
|
+
cp "$ROOT_DIR/systemd/discstation.service" "$HOME/.config/systemd/user/discstation.service"
|
|
51
|
+
systemctl --user daemon-reload
|
|
52
|
+
systemctl --user enable --now discstation.service
|
|
53
|
+
|
|
54
|
+
printf '\nDiscStation installed. Log out/in if device permissions changed.\n'
|
|
55
|
+
printf 'App: %s\n' "$APP_DIR"
|
|
56
|
+
printf 'Web: https://%s:8080\n' "$(hostname -I | awk '{print $1}')"
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "discstation",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "DiscStation optical-media appliance host — one cross-OS installer",
|
|
5
|
+
"bin": {
|
|
6
|
+
"discstation-setup": "scripts/setup.mjs"
|
|
7
|
+
},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"setup": "node scripts/setup.mjs"
|
|
10
|
+
},
|
|
11
|
+
"engines": {
|
|
12
|
+
"node": ">=16"
|
|
13
|
+
},
|
|
14
|
+
"os": [
|
|
15
|
+
"linux",
|
|
16
|
+
"darwin",
|
|
17
|
+
"win32"
|
|
18
|
+
],
|
|
19
|
+
"files": [
|
|
20
|
+
"scripts/",
|
|
21
|
+
"src/*.py",
|
|
22
|
+
"src/static/",
|
|
23
|
+
"arduino/",
|
|
24
|
+
"systemd/",
|
|
25
|
+
"docs/",
|
|
26
|
+
"install.sh",
|
|
27
|
+
"install-macos.sh",
|
|
28
|
+
"install-windows.ps1",
|
|
29
|
+
"requirements.txt",
|
|
30
|
+
"discstation.env.example",
|
|
31
|
+
"README.md",
|
|
32
|
+
"LICENSE"
|
|
33
|
+
],
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "git+https://github.com/phuju/dvd-station.git"
|
|
37
|
+
},
|
|
38
|
+
"keywords": [
|
|
39
|
+
"dvd",
|
|
40
|
+
"cd",
|
|
41
|
+
"optical",
|
|
42
|
+
"burn",
|
|
43
|
+
"rip",
|
|
44
|
+
"appliance"
|
|
45
|
+
],
|
|
46
|
+
"license": "MIT",
|
|
47
|
+
"private": false
|
|
48
|
+
}
|
package/requirements.txt
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# DiscStation Python dependencies.
|
|
2
|
+
#
|
|
3
|
+
# On Debian/Ubuntu, prefer the system packages (see install.sh):
|
|
4
|
+
# python3-serial python3-mutagen python3-requests python3-pyudev
|
|
5
|
+
# python3-libdiscid python3-musicbrainzngs
|
|
6
|
+
# The pip names below are for venv / macOS / Windows installs.
|
|
7
|
+
|
|
8
|
+
pyserial>=3.5
|
|
9
|
+
mutagen>=1.45
|
|
10
|
+
requests>=2.28
|
|
11
|
+
yt-dlp>=2024.1.1
|
|
12
|
+
|
|
13
|
+
# Disc detection / metadata (all optional at runtime: the code degrades to the
|
|
14
|
+
# previous subprocess-based paths if an import fails).
|
|
15
|
+
pyudev>=0.24 ; sys_platform == "linux"
|
|
16
|
+
python-libdiscid>=2.0 ; sys_platform != "win32"
|
|
17
|
+
musicbrainzngs>=0.7.1
|
|
18
|
+
|
|
19
|
+
# Video metadata (TMDb). Needs DISCSTATION_TMDB_API_KEY to do anything.
|
|
20
|
+
tmdbsimple>=2.9
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// One entry point for installing the DiscStation host on any OS.
|
|
3
|
+
// It just dispatches to the platform installer that already exists in the repo
|
|
4
|
+
// (install.sh / install-macos.sh / install-windows.ps1); extra CLI args and the
|
|
5
|
+
// DISCSTATION_* / DISC_* env vars are forwarded through.
|
|
6
|
+
|
|
7
|
+
import { spawnSync } from 'node:child_process';
|
|
8
|
+
import { existsSync } from 'node:fs';
|
|
9
|
+
import { dirname, join, resolve } from 'node:path';
|
|
10
|
+
import { fileURLToPath } from 'node:url';
|
|
11
|
+
|
|
12
|
+
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
13
|
+
const args = process.argv.slice(2);
|
|
14
|
+
|
|
15
|
+
if (args.includes('-h') || args.includes('--help')) {
|
|
16
|
+
process.stdout.write(
|
|
17
|
+
`discstation-setup — install the DiscStation host
|
|
18
|
+
|
|
19
|
+
Runs the installer for the current OS:
|
|
20
|
+
linux install.sh full: apt deps, venv, systemd --user service, self-signed cert
|
|
21
|
+
darwin install-macos.sh full: Homebrew deps, venv, launchd agent, cert (optical is experimental)
|
|
22
|
+
windows install-windows.ps1 files + venv only; web/serial control, no burn backend
|
|
23
|
+
|
|
24
|
+
Prereqs: Node 16+, Python 3 (python3 / py on PATH), and either bash (linux/macOS)
|
|
25
|
+
or PowerShell (Windows). Homebrew is auto-installed on macOS if missing; the
|
|
26
|
+
Linux script uses sudo for apt + group membership.
|
|
27
|
+
|
|
28
|
+
Env vars (forwarded): DISCSTATION_APP_DIR, DISCSTATION_VENV_DIR,
|
|
29
|
+
DISCSTATION_CONFIG_DIR, DISCSTATION_HTTP_PORT, DISC_DEVICE, DISC_PORT.
|
|
30
|
+
|
|
31
|
+
Any extra arguments are passed straight to the platform script.
|
|
32
|
+
`
|
|
33
|
+
);
|
|
34
|
+
process.exit(0);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function run(cmd, cmdArgs) {
|
|
38
|
+
const r = spawnSync(cmd, cmdArgs, { stdio: 'inherit', cwd: ROOT });
|
|
39
|
+
if (r.error) {
|
|
40
|
+
console.error(`\n${cmd}: ${r.error.message}`);
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
process.exit(r.status ?? 1);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function needPython(bin) {
|
|
47
|
+
const r = spawnSync(bin, ['--version'], { stdio: 'ignore' });
|
|
48
|
+
return r.status === 0;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
switch (process.platform) {
|
|
52
|
+
case 'linux':
|
|
53
|
+
case 'darwin': {
|
|
54
|
+
const script = process.platform === 'linux' ? 'install.sh' : 'install-macos.sh';
|
|
55
|
+
if (!needPython('python3')) {
|
|
56
|
+
console.error('Python 3 not found on PATH. Install it first, then re-run.');
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
run('bash', [join(ROOT, script), ...args]);
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
case 'win32': {
|
|
63
|
+
if (!needPython('py') && !needPython('python')) {
|
|
64
|
+
console.error('Python 3 not found. Install from https://www.python.org/downloads/windows/');
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
const ps1 = join(ROOT, 'install-windows.ps1');
|
|
68
|
+
if (!existsSync(ps1)) {
|
|
69
|
+
console.error('install-windows.ps1 missing from the package.');
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
run('powershell.exe', ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', ps1, ...args]);
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
default:
|
|
76
|
+
console.error(`Unsupported platform: ${process.platform}. Run one of the install.* scripts by hand.`);
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|