discstation 0.1.18 → 0.1.21
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/README.md +7 -5
- package/arduino/c6/DiscStation_C6.ino +7 -1
- package/arduino/v1/DiscStation.ino +4 -1
- package/docs/PLATFORM_SUPPORT.md +24 -5
- package/install-windows.ps1 +162 -18
- package/package.json +2 -1
- package/scripts/setup.mjs +1 -1
- package/src/discstation.py +522 -120
- package/src/discstation_burn.py +167 -8
- package/src/discstation_host.py +122 -3
- package/src/static/app.js +72 -0
- package/src/static/index.html +37 -3
- package/src/static/style.css +38 -0
- package/src/win/_json.ps1 +29 -0
- package/src/win/audio-toc.ps1 +43 -0
- package/src/win/burn-audio.ps1 +87 -0
- package/src/win/burn-data.ps1 +83 -0
- package/src/win/burn-image.ps1 +68 -0
- package/src/win/disc-info.ps1 +81 -0
- package/src/win/eject.ps1 +30 -0
- package/src/win/play-audio-cd.ps1 +94 -0
package/README.md
CHANGED
|
@@ -64,7 +64,7 @@ Windows.
|
|
|
64
64
|
|----|-----------|-----------------|
|
|
65
65
|
| Linux | `install.sh` — apt deps, venv, systemd `--user` service, self-signed cert | full burn / rip / play |
|
|
66
66
|
| macOS | `install-macos.sh` — Homebrew deps, venv, launchd agent, cert | burn / rip / play (audio-CD *burning* is best-effort; set `DISC_DEVICE` if detection fails) |
|
|
67
|
-
| Windows | `install-windows.ps1` —
|
|
67
|
+
| Windows | `install-windows.ps1` — Python + venv, self-signed cert, firewall rules, auto-start Scheduled Task | burn (ISO / data / audio CD) via IMAPI2 on Windows 10/11 and 7; DVD rip (HandBrake main-feature mode) and play (mpv) use the shared cross-platform path; full VIDEO_TS mirror rip and audio-CD rip aren't implemented on Windows yet |
|
|
68
68
|
|
|
69
69
|
### Or run the platform script directly
|
|
70
70
|
|
|
@@ -80,7 +80,7 @@ arduino-cli lib install QRCode
|
|
|
80
80
|
# macOS host
|
|
81
81
|
./install-macos.sh
|
|
82
82
|
|
|
83
|
-
# Windows host
|
|
83
|
+
# Windows host
|
|
84
84
|
PowerShell -ExecutionPolicy Bypass -File .\install-windows.ps1
|
|
85
85
|
```
|
|
86
86
|
|
|
@@ -88,8 +88,10 @@ PowerShell -ExecutionPolicy Bypass -File .\install-windows.ps1
|
|
|
88
88
|
|
|
89
89
|
Linux and macOS both run the complete optical workflow (burn, rip, play) —
|
|
90
90
|
macOS via `xorriso` / `hdiutil` / `cd-paranoia` / `dvdbackup` / HandBrake, with
|
|
91
|
-
audio-CD *burning* the one best-effort area. Windows
|
|
92
|
-
|
|
91
|
+
audio-CD *burning* the one best-effort area. Windows burns (ISO / data / audio
|
|
92
|
+
CD) via IMAPI2 and plays via mpv; DVD ripping works in HandBrake main-feature
|
|
93
|
+
mode but not full VIDEO_TS mirror or audio-CD ripping yet. See
|
|
94
|
+
`docs/PLATFORM_SUPPORT.md`.
|
|
93
95
|
|
|
94
96
|
## Web Interface
|
|
95
97
|
|
|
@@ -114,7 +116,7 @@ Built-in web server on port 8080 (HTTPS with self-signed cert):
|
|
|
114
116
|
| `DISC_CLEANUP_DAYS` | 2 | Auto-cleanup old job directories |
|
|
115
117
|
| `DISC_OUTPUT_LIMIT_BYTES` | 4300000000 | Conservative DVD5 payload limit |
|
|
116
118
|
| `DISC_DL_OUTPUT_LIMIT_BYTES` | 8000000000 | Conservative DVD9 payload limit |
|
|
117
|
-
| `DISC_DEVICE` | auto | Optical drive node override
|
|
119
|
+
| `DISC_DEVICE` | auto | Optical drive node override |
|
|
118
120
|
| `DISC_PORT` | auto | ESP32 serial port override |
|
|
119
121
|
| `DISCSTATION_HTTP_PORT` | 8081 | Plain-HTTP port for the mobile app (`0` disables) |
|
|
120
122
|
| `DISCSTATION_DVD_RIP_MODE` | mirror | `mkv` = HandBrake main-feature transcode instead of a full VIDEO_TS mirror |
|
|
@@ -510,7 +510,13 @@ void parseMessage(String msg) {
|
|
|
510
510
|
line1 = msg.substring(7);
|
|
511
511
|
line2 = "";
|
|
512
512
|
line3 = "";
|
|
513
|
-
progressPercent
|
|
513
|
+
// Don't reset progressPercent here - a STATUS: label change (e.g.
|
|
514
|
+
// "Copying files..." -> "Converting...") is often immediately
|
|
515
|
+
// followed by a fresh PROGRESS: for the same ongoing operation.
|
|
516
|
+
// Wiping it every time flipped the bar to the indeterminate dots
|
|
517
|
+
// and back on every single label update, flickering between the
|
|
518
|
+
// two. DONE:/CANCELLED:/ERROR:/NO_DISC: still reset it below - those
|
|
519
|
+
// really are the end of an operation.
|
|
514
520
|
drawStatus();
|
|
515
521
|
|
|
516
522
|
} else if (msg.startsWith("PROGRESS:")) {
|
|
@@ -535,7 +535,10 @@ void parseMessage(String msg) {
|
|
|
535
535
|
line1 = msg.substring(7);
|
|
536
536
|
line2 = "";
|
|
537
537
|
line3 = "";
|
|
538
|
-
progressPercent
|
|
538
|
+
// Don't reset progressPercent here - see arduino/c6/DiscStation_C6.ino's
|
|
539
|
+
// matching comment: STATUS: label changes mid-operation are usually
|
|
540
|
+
// immediately followed by a fresh PROGRESS:, so wiping it every time
|
|
541
|
+
// flickered the bar to the indeterminate dots and back.
|
|
539
542
|
drawStatus();
|
|
540
543
|
|
|
541
544
|
} else if (msg.startsWith("PROGRESS:")) {
|
package/docs/PLATFORM_SUPPORT.md
CHANGED
|
@@ -29,10 +29,28 @@ the drive on recent macOS; DiscStation reports this clearly instead of hanging.
|
|
|
29
29
|
|
|
30
30
|
## Windows
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
Runs the same Python host and web UI as Linux/macOS, triggered the same way
|
|
33
|
+
via the ESP32 OLED remote. `install-windows.ps1` sets up Python + venv, a
|
|
34
|
+
self-signed cert, firewall rules for 8080/8081, and a per-user auto-start
|
|
35
|
+
Scheduled Task (headless `pythonw.exe`, no admin needed).
|
|
36
|
+
|
|
37
|
+
- **Detect / eject** — WMI (`Win32_CDROMDrive`, `Win32_LogicalDisk`) + IMAPI2
|
|
38
|
+
for media type, blank/rewritable state, and capacity
|
|
39
|
+
(`src/win/disc-info.ps1`, `src/win/eject.ps1`).
|
|
40
|
+
- **Burn** — data, ISO, and audio CD all go through IMAPI2
|
|
41
|
+
(`src/win/burn-{image,data,audio}.ps1`), with live progress streamed to the
|
|
42
|
+
OLED; `isoburn.exe /q` is the zero-dependency fallback for a raw ISO.
|
|
43
|
+
Works on Windows 7 SP1 and 10/11.
|
|
44
|
+
- **Rip** — DVD main-feature mode via HandBrakeCLI (winget on 10/11) works;
|
|
45
|
+
a full unencrypted VIDEO_TS mirror and audio-CD ripping aren't implemented
|
|
46
|
+
yet (no Windows path for `dvdbackup`/`cd-paranoia`).
|
|
47
|
+
- **Play** — `mpv`, via the same code path as Linux/macOS (device letter for
|
|
48
|
+
DVD-Video, `cdda://` for audio CD, mounted drive for data/VCD).
|
|
49
|
+
|
|
50
|
+
Windows 7 (no `winget`) gets the host, detection, eject, and all three burn
|
|
51
|
+
modes; rip/play need tools that don't install cleanly on 7, so those OLED
|
|
52
|
+
actions report "not supported" there. Set `DISC_DEVICE` to override drive
|
|
53
|
+
auto-detection.
|
|
36
54
|
|
|
37
55
|
## Shared Components
|
|
38
56
|
|
|
@@ -43,4 +61,5 @@ instead of silently attempting Linux commands.
|
|
|
43
61
|
- QR-code web URL display
|
|
44
62
|
|
|
45
63
|
The optical-drive backend is the platform boundary. Linux and macOS are
|
|
46
|
-
complete (bar macOS audio-CD burning); Windows
|
|
64
|
+
complete (bar macOS audio-CD burning); Windows burns and plays, with DVD-mirror
|
|
65
|
+
and audio-CD ripping still to come.
|
package/install-windows.ps1
CHANGED
|
@@ -1,29 +1,173 @@
|
|
|
1
|
+
# DiscStation host installer for Windows 10/11 (and best-effort on 7 SP1).
|
|
2
|
+
# powershell -ExecutionPolicy Bypass -File install-windows.ps1
|
|
3
|
+
# Sets up: Python + venv, optical CLI tools (winget), self-signed cert,
|
|
4
|
+
# a per-user auto-start Scheduled Task, and inbound firewall rules for 8080/8081.
|
|
1
5
|
$ErrorActionPreference = "Stop"
|
|
6
|
+
$ProgressPreference = "SilentlyContinue" # Invoke-WebRequest's progress bar breaks over SSH/non-interactive hosts
|
|
2
7
|
|
|
3
|
-
$Root
|
|
4
|
-
$
|
|
5
|
-
$
|
|
8
|
+
$Root = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
9
|
+
$Base = if ($env:DISCSTATION_CONFIG_DIR) { $env:DISCSTATION_CONFIG_DIR } else { Join-Path $env:APPDATA "DiscStation" }
|
|
10
|
+
$App = if ($env:DISCSTATION_APP_DIR) { $env:DISCSTATION_APP_DIR } else { Join-Path $Base "app" }
|
|
11
|
+
$Venv = if ($env:DISCSTATION_VENV_DIR) { $env:DISCSTATION_VENV_DIR } else { Join-Path $Base "venv" }
|
|
12
|
+
$IsWin7 = [Environment]::OSVersion.Version.Major -eq 6
|
|
13
|
+
$winget = (Get-Command winget -ErrorAction SilentlyContinue)
|
|
6
14
|
|
|
7
|
-
|
|
8
|
-
|
|
15
|
+
function Have($name) { [bool](Get-Command $name -ErrorAction SilentlyContinue) }
|
|
16
|
+
function Winget-Install($id) {
|
|
17
|
+
if (-not $winget) { return $false }
|
|
18
|
+
try { winget install -e --id $id --accept-source-agreements --accept-package-agreements --silent | Out-Null; return $true }
|
|
19
|
+
catch { Write-Host " winget $id failed (skipping)"; return $false }
|
|
9
20
|
}
|
|
10
21
|
|
|
11
|
-
|
|
22
|
+
# --- 1. Python -------------------------------------------------------------------
|
|
23
|
+
if (-not (Have "python") -and -not (Have "py")) {
|
|
24
|
+
Write-Host "Installing Python..."
|
|
25
|
+
if ($winget -and -not $IsWin7) {
|
|
26
|
+
Winget-Install "Python.Python.3.12" | Out-Null
|
|
27
|
+
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "User") + ";" + $env:Path
|
|
28
|
+
} else {
|
|
29
|
+
$pyver = if ($IsWin7) { "3.8.10" } else { "3.12.6" }
|
|
30
|
+
$url = "https://www.python.org/ftp/python/$pyver/python-$pyver-amd64.exe"
|
|
31
|
+
$exe = Join-Path $env:TEMP "python-$pyver-amd64.exe"
|
|
32
|
+
Invoke-WebRequest $url -OutFile $exe -UseBasicParsing
|
|
33
|
+
Start-Process $exe -ArgumentList "/quiet","InstallAllUsers=0","PrependPath=1","Include_test=0" -Wait
|
|
34
|
+
$env:Path = (Join-Path $env:LOCALAPPDATA "Programs\Python\Python$($pyver.Substring(0,4) -replace '\.','')") + ";" + $env:Path + ";" +
|
|
35
|
+
(Join-Path $env:LOCALAPPDATA "Programs\Python\Python$($pyver.Substring(0,4) -replace '\.','')\Scripts")
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (Have "python") { $PyExe = "python"; $PyArgs = @() }
|
|
39
|
+
elseif (Have "py") { $PyExe = "py"; $PyArgs = @("-3") }
|
|
40
|
+
else { throw "Python install failed. Install Python 3 manually and re-run." }
|
|
41
|
+
|
|
42
|
+
# --- 2. Optical CLI tools (winget when available; Win10/11 only; best-effort,
|
|
43
|
+
# strictly time-bounded so a slow/blocked mirror can never hang the install) --
|
|
44
|
+
if ($winget -and -not $IsWin7) {
|
|
45
|
+
Write-Host "Installing optical tools via winget (best effort)..."
|
|
46
|
+
foreach ($id in "libburnia.xorriso","mpv.mpv","HandBrake.HandBrake.CLI","Gyan.FFmpeg","yt-dlp.yt-dlp") {
|
|
47
|
+
Winget-Install $id | Out-Null
|
|
48
|
+
}
|
|
49
|
+
} elseif (-not $IsWin7) {
|
|
50
|
+
Write-Host "winget unavailable - fetching optical tools directly (best effort, 25s timeout each)..."
|
|
51
|
+
$tools = Join-Path $Base "tools"
|
|
52
|
+
New-Item -ItemType Directory -Force -Path $tools | Out-Null
|
|
53
|
+
function Get-Zip($url, $dest) {
|
|
54
|
+
try {
|
|
55
|
+
$zip = Join-Path $env:TEMP ([IO.Path]::GetFileName($url))
|
|
56
|
+
Invoke-WebRequest $url -OutFile $zip -UseBasicParsing -TimeoutSec 25
|
|
57
|
+
Expand-Archive -Path $zip -DestinationPath $dest -Force
|
|
58
|
+
Remove-Item $zip -ErrorAction SilentlyContinue
|
|
59
|
+
return $true
|
|
60
|
+
} catch { Write-Host " fetch failed: $url"; return $false }
|
|
61
|
+
}
|
|
62
|
+
if (-not (Have "yt-dlp")) {
|
|
63
|
+
try { Invoke-WebRequest "https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp.exe" -OutFile (Join-Path $tools "yt-dlp.exe") -UseBasicParsing -TimeoutSec 25 }
|
|
64
|
+
catch { Write-Host " yt-dlp fetch skipped" }
|
|
65
|
+
}
|
|
66
|
+
if (-not (Have "ffmpeg")) { Get-Zip "https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.zip" $tools | Out-Null }
|
|
67
|
+
if (-not (Have "mpv")) {
|
|
68
|
+
# The SourceForge "latest" mpv build is a .7z (Expand-Archive can't
|
|
69
|
+
# open it); mpv's own first-party CI release ships plain .zip builds.
|
|
70
|
+
try {
|
|
71
|
+
$mpvRelease = Invoke-RestMethod "https://api.github.com/repos/mpv-player/mpv/releases/tags/git-release" -UseBasicParsing -TimeoutSec 25
|
|
72
|
+
$mpvAsset = $mpvRelease.assets | Where-Object { $_.name -match "x86_64-w64-mingw32\.zip$" } | Select-Object -First 1
|
|
73
|
+
if ($mpvAsset) { Get-Zip $mpvAsset.browser_download_url (Join-Path $tools "mpv") | Out-Null }
|
|
74
|
+
} catch { Write-Host " mpv fetch skipped" }
|
|
75
|
+
}
|
|
76
|
+
if (-not (Have "HandBrakeCLI")) {
|
|
77
|
+
try {
|
|
78
|
+
$hbRelease = Invoke-RestMethod "https://api.github.com/repos/HandBrake/HandBrake/releases/latest" -UseBasicParsing -TimeoutSec 25
|
|
79
|
+
$hbAsset = $hbRelease.assets | Where-Object { $_.name -match "^HandBrakeCLI-.*-win-x86_64\.zip$" } | Select-Object -First 1
|
|
80
|
+
if ($hbAsset) { Get-Zip $hbAsset.browser_download_url (Join-Path $tools "handbrake") | Out-Null }
|
|
81
|
+
} catch { Write-Host " HandBrakeCLI fetch skipped" }
|
|
82
|
+
}
|
|
83
|
+
# dvdauthor + spumux (DVD-Video authoring/subtitles) have no winget package;
|
|
84
|
+
# this VideoHelp-hosted plain .zip (no rar/unrar needed) is the only
|
|
85
|
+
# reliable direct-download source found.
|
|
86
|
+
if (-not (Have "dvdauthor")) { Get-Zip "https://download.videohelp.com/gfd/edcounter.php?file=download/dvdauthor_winbin.zip" (Join-Path $tools "dvdauthor") | Out-Null }
|
|
87
|
+
if (Test-Path $tools) {
|
|
88
|
+
$env:Path = $env:Path + ";" + $tools + ";" +
|
|
89
|
+
((Get-ChildItem $tools -Recurse -Filter "ffmpeg.exe" -ErrorAction SilentlyContinue | Select-Object -First 1).DirectoryName)
|
|
90
|
+
}
|
|
91
|
+
Write-Host "xorriso and HandBrakeCLI have no simple direct-download URL - install manually if you need"
|
|
92
|
+
Write-Host "video-DVD ISO packaging / DVD ripping (see the plan's Windows setup notes)."
|
|
93
|
+
} else {
|
|
94
|
+
Write-Host "winget unavailable (Windows 7). ISO + data + audio burn work via IMAPI2."
|
|
95
|
+
Write-Host "For rip/play/video-DVD install manually: xorriso, HandBrakeCLI 1.5.1, ffmpeg, mpv, yt-dlp."
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
# --- 3. App files + venv ------------------------------------------------------
|
|
99
|
+
New-Item -ItemType Directory -Force -Path $Base, $App | Out-Null
|
|
12
100
|
Copy-Item -Recurse -Force (Join-Path $Root "src\*") $App
|
|
13
|
-
|
|
14
|
-
& (Join-Path $Venv "Scripts\python.exe") -m pip install --upgrade pip
|
|
101
|
+
& $PyExe @PyArgs -m venv $Venv
|
|
15
102
|
$Py = Join-Path $Venv "Scripts\python.exe"
|
|
103
|
+
& $Py -m pip install --upgrade pip
|
|
16
104
|
$Req = Join-Path $Root "requirements.txt"
|
|
17
|
-
if (Test-Path $Req) {
|
|
18
|
-
|
|
19
|
-
} else {
|
|
20
|
-
|
|
105
|
+
if (Test-Path $Req) { & $Py -m pip install -r $Req } else { & $Py -m pip install pyserial mutagen requests yt-dlp }
|
|
106
|
+
$Opt = Join-Path $Root "requirements-optional.txt"
|
|
107
|
+
try { if (Test-Path $Opt) { & $Py -m pip install -r $Opt } else { & $Py -m pip install musicbrainzngs tmdbsimple } }
|
|
108
|
+
catch { Write-Host "Optional metadata deps skipped (host still works)." }
|
|
109
|
+
|
|
110
|
+
# --- 4. Self-signed cert (HTTPS on :8080; :8081 works without it) --------------
|
|
111
|
+
$crt = Join-Path $Base "server.crt"; $key = Join-Path $Base "server.key"
|
|
112
|
+
if (-not (Test-Path $crt) -or -not (Test-Path $key)) {
|
|
113
|
+
try {
|
|
114
|
+
$c = New-SelfSignedCertificate -DnsName "discstation.local" -CertStoreLocation "Cert:\CurrentUser\My" -NotAfter (Get-Date).AddYears(10)
|
|
115
|
+
$pwd = ConvertTo-SecureString -String "discstation" -Force -AsPlainText
|
|
116
|
+
$pfx = Join-Path $env:TEMP "ds.pfx"
|
|
117
|
+
Export-PfxCertificate -Cert $c -FilePath $pfx -Password $pwd | Out-Null
|
|
118
|
+
& $Py -c "import ssl" 2>$null
|
|
119
|
+
# Convert PFX -> PEM via Python cryptography if present, else leave HTTPS off.
|
|
120
|
+
& $Py -m pip install cryptography 2>$null
|
|
121
|
+
& $Py -c "import sys;from cryptography.hazmat.primitives.serialization import pkcs12,Encoding,PrivateFormat,NoEncryption;d=open(sys.argv[1],'rb').read();k,c,_=pkcs12.load_key_and_certificates(d,b'discstation');open(sys.argv[2],'wb').write(c.public_bytes(Encoding.PEM));open(sys.argv[3],'wb').write(k.private_bytes(Encoding.PEM,PrivateFormat.TraditionalOpenSSL,NoEncryption()))" $pfx $crt $key
|
|
122
|
+
Remove-Item $pfx -ErrorAction SilentlyContinue
|
|
123
|
+
} catch { Write-Host "Cert generation skipped; the host will serve plain HTTP on 8081." }
|
|
21
124
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
125
|
+
|
|
126
|
+
# --- 5. Firewall -------------------------------------------------------------
|
|
127
|
+
foreach ($port in 8080, 8081) {
|
|
128
|
+
$name = "DiscStation $port"
|
|
129
|
+
try {
|
|
130
|
+
if (Get-Command New-NetFirewallRule -ErrorAction SilentlyContinue) {
|
|
131
|
+
if (-not (Get-NetFirewallRule -DisplayName $name -ErrorAction SilentlyContinue)) {
|
|
132
|
+
New-NetFirewallRule -DisplayName $name -Direction Inbound -Action Allow -Protocol TCP -LocalPort $port | Out-Null
|
|
133
|
+
}
|
|
134
|
+
} else {
|
|
135
|
+
netsh advfirewall firewall add rule name="$name" dir=in action=allow protocol=TCP localport=$port | Out-Null
|
|
136
|
+
}
|
|
137
|
+
} catch {}
|
|
25
138
|
}
|
|
26
139
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
140
|
+
# --- 6. Auto-start Scheduled Task -----------------------------------------------
|
|
141
|
+
$pyw = Join-Path $Venv "Scripts\pythonw.exe"
|
|
142
|
+
$target = Join-Path $App "discstation.py"
|
|
143
|
+
try {
|
|
144
|
+
if (Get-Command Register-ScheduledTask -ErrorAction SilentlyContinue) {
|
|
145
|
+
$action = New-ScheduledTaskAction -Execute $pyw -Argument "`"$target`"" -WorkingDirectory $App
|
|
146
|
+
$trigger = New-ScheduledTaskTrigger -AtLogOn -User $env:USERNAME
|
|
147
|
+
$set = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 1)
|
|
148
|
+
# Interactive: attaches to the logged-in desktop session, same
|
|
149
|
+
# lifecycle as `systemctl --user`/launchd LaunchAgents on the other
|
|
150
|
+
# two platforms - required so PLAY's mpv window actually renders
|
|
151
|
+
# somewhere visible (S4U runs headlessly with no session to render
|
|
152
|
+
# into, which silently made every mpv window invisible). Trade-off,
|
|
153
|
+
# same one Linux/macOS already accept: won't start until someone is
|
|
154
|
+
# logged into the desktop.
|
|
155
|
+
# RunLevel Limited (standard, non-elevated): nothing here needs admin -
|
|
156
|
+
# IMAPI2 burning, WMI reads, and binding ports >1024 all work as a normal
|
|
157
|
+
# user, and elevation is what put "Administrator" on the flashing console
|
|
158
|
+
# windows this used to spawn.
|
|
159
|
+
$principal = New-ScheduledTaskPrincipal -UserId $env:USERNAME -LogonType Interactive -RunLevel Limited
|
|
160
|
+
Register-ScheduledTask -TaskName "DiscStation" -Action $action -Trigger $trigger -Settings $set -Principal $principal -Force | Out-Null
|
|
161
|
+
Start-ScheduledTask -TaskName "DiscStation"
|
|
162
|
+
} else {
|
|
163
|
+
schtasks /create /tn "DiscStation" /sc onlogon /f /tr "`"$pyw`" `"$target`"" | Out-Null
|
|
164
|
+
schtasks /run /tn "DiscStation" | Out-Null
|
|
165
|
+
}
|
|
166
|
+
} catch { Write-Host "Auto-start task not created: $_" }
|
|
167
|
+
|
|
168
|
+
$ip = (Get-NetIPAddress -AddressFamily IPv4 -ErrorAction SilentlyContinue | Where-Object { $_.IPAddress -notmatch '^127\.|^169\.254\.' } | Select-Object -First 1).IPAddress
|
|
169
|
+
Write-Host ""
|
|
170
|
+
Write-Host "DiscStation installed at $App"
|
|
171
|
+
Write-Host " Web UI: http://localhost:8081/ (also http://$ip`:8081 on the LAN)"
|
|
172
|
+
Write-Host " Run 'discstation' any time to open it. Detection/eject/ISO+data+audio burn use IMAPI2 (no extra tools)."
|
|
173
|
+
try { node (Join-Path $Root "scripts\open.mjs") } catch {}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "discstation",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.21",
|
|
4
4
|
"description": "DiscStation optical-media appliance host — one cross-OS installer",
|
|
5
5
|
"bin": {
|
|
6
6
|
"discstation-setup": "scripts/setup.mjs",
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"scripts/",
|
|
22
22
|
"src/*.py",
|
|
23
23
|
"src/static/",
|
|
24
|
+
"src/win/",
|
|
24
25
|
"arduino/",
|
|
25
26
|
"systemd/",
|
|
26
27
|
"docs/",
|
package/scripts/setup.mjs
CHANGED
|
@@ -19,7 +19,7 @@ if (args.includes('-h') || args.includes('--help')) {
|
|
|
19
19
|
Runs the installer for the current OS:
|
|
20
20
|
linux install.sh full: apt deps, venv, systemd --user service, self-signed cert
|
|
21
21
|
darwin install-macos.sh full: Homebrew deps, venv, launchd agent, cert (audio-CD burn is best-effort)
|
|
22
|
-
windows install-windows.ps1
|
|
22
|
+
windows install-windows.ps1 venv + cert + firewall + auto-start task; burn via IMAPI2 (10/11 and 7)
|
|
23
23
|
|
|
24
24
|
Prereqs: Node 16+, Python 3 (python3 / py on PATH), and either bash (linux/macOS)
|
|
25
25
|
or PowerShell (Windows). Homebrew is auto-installed on macOS if missing; the
|