Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2123764b18 |
No files matched your search
+86
-10
@@ -125,6 +125,22 @@ def powershell_exe():
|
||||
return path if os.path.exists(path) else "powershell.exe"
|
||||
|
||||
|
||||
def clean_env():
|
||||
"""去掉 PyInstaller 的 _PYI_* / PYINSTALLER_* 变量后再启动子进程。
|
||||
|
||||
单文件程序解压到 %TEMP%\\_MEIxxxxxx,并通过 _PYI_APPLICATION_HOME_DIR
|
||||
把这个路径告诉子进程。更新脚本本身是从播放器内部启动的,会一路继承到
|
||||
新拉起的 exe 上,导致新实例复用旧解压目录;而旧进程退出时正在删除该
|
||||
目录,于是出现 "Failed to load Python DLL ... 找不到指定的模块"。
|
||||
"""
|
||||
env = os.environ.copy()
|
||||
for key in list(env):
|
||||
upper = str(key).upper()
|
||||
if upper.startswith("_PYI") or upper.startswith("PYINSTALLER_"):
|
||||
env.pop(key, None)
|
||||
return env
|
||||
|
||||
|
||||
def build_install_script(current, downloaded, pid, digest="", parent_pid=None):
|
||||
"""生成 Unicode 安全的更新脚本:校验副本后再交换文件,任何失败路径都会重新拉起程序。"""
|
||||
current = os.path.abspath(current)
|
||||
@@ -148,20 +164,65 @@ function Write-UpdateLog($message) {
|
||||
Add-Content -LiteralPath $log -Encoding UTF8 -Value ("[" + (Get-Date -Format 'yyyy-MM-dd HH:mm:ss') + "] " + $message)
|
||||
} catch {}
|
||||
}
|
||||
# 新实例必须自己解压,不能复用本进程(以及旧播放器)的 _MEI 目录。
|
||||
# 而且 _MEI 目录名是按 pid 编码的,旧进程延迟清理时可能撞掉新进程刚建好的
|
||||
# 同名目录(pid 复用),于是出现 "Failed to load Python DLL"。把新实例的运行
|
||||
# 临时目录挪到我们自己的目录下,彻底避开这种竞争。
|
||||
$runtime = Join-Path (Split-Path -Parent $logDir) "runtime"
|
||||
function Prepare-Runtime {
|
||||
try {
|
||||
New-Item -ItemType Directory -Force -Path $runtime | Out-Null
|
||||
# 不用 Get-ChildItem -Directory,兼容 Windows 7 自带的 PowerShell 2.0
|
||||
Get-ChildItem -LiteralPath $runtime -Force -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.PSIsContainer -and $_.Name -like "_MEI*" } |
|
||||
Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
|
||||
$env:TEMP = $runtime
|
||||
$env:TMP = $runtime
|
||||
Write-UpdateLog ("runtime temp -> " + $runtime)
|
||||
} catch {
|
||||
Write-UpdateLog ("runtime temp failed: " + $_.Exception.Message)
|
||||
}
|
||||
}
|
||||
function Get-Sha256($path) {
|
||||
$stream = [System.IO.File]::Open($path, 'Open', 'Read', 'Read')
|
||||
try {
|
||||
$sha = New-Object System.Security.Cryptography.SHA256Managed
|
||||
$bytes = $sha.ComputeHash($stream)
|
||||
$sb = New-Object System.Text.StringBuilder
|
||||
foreach ($b in $bytes) { [void]$sb.Append($b.ToString('x2')) }
|
||||
return $sb.ToString()
|
||||
} finally {
|
||||
$stream.Close()
|
||||
}
|
||||
}
|
||||
function Clear-FrozenEnv {
|
||||
foreach ($name in @('_PYI_APPLICATION_HOME_DIR','_PYI_ARCHIVE_FILE','_PYI_PARENT_PROCESS_LEVEL','_PYI_SPLASH_IPC','PYINSTALLER_RESET_ENVIRONMENT','PYINSTALLER_STRICT_UNPACK_MODE','PYINSTALLER_SUPPRESS_SPLASH_SCREEN')) {
|
||||
Remove-Item -Path ("Env:\" + $name) -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
function Start-App($path) {
|
||||
if (-not $path) { return $false }
|
||||
if (-not (Test-Path -LiteralPath $path)) {
|
||||
Write-UpdateLog ("missing target: " + $path)
|
||||
return $false
|
||||
}
|
||||
try {
|
||||
Start-Process -FilePath $path -WorkingDirectory (Split-Path -Parent $path) -ErrorAction Stop
|
||||
Write-UpdateLog ("started: " + $path)
|
||||
return $true
|
||||
} catch {
|
||||
Write-UpdateLog ("start failed: " + $path + " :: " + $_.Exception.Message)
|
||||
return $false
|
||||
Clear-FrozenEnv
|
||||
Prepare-Runtime
|
||||
for ($attempt = 1; $attempt -le 3; $attempt++) {
|
||||
try {
|
||||
$proc = Start-Process -FilePath $path -WorkingDirectory (Split-Path -Parent $path) -PassThru -ErrorAction Stop
|
||||
Start-Sleep -Milliseconds 2000
|
||||
if (-not $proc.HasExited) {
|
||||
Write-UpdateLog ("started: " + $path + " (pid=" + $proc.Id + ")")
|
||||
return $true
|
||||
}
|
||||
Write-UpdateLog ("process exited at once, attempt " + $attempt)
|
||||
} catch {
|
||||
Write-UpdateLog ("start failed: " + $path + " :: " + $_.Exception.Message)
|
||||
}
|
||||
Start-Sleep -Milliseconds 1500
|
||||
}
|
||||
return $false
|
||||
}
|
||||
|
||||
Write-UpdateLog "=== update begin; pids=__PIDS_TEXT__ ==="
|
||||
@@ -171,7 +232,19 @@ Start-Sleep -Seconds 2
|
||||
foreach ($p in @(__PIDS__)) {
|
||||
try { Stop-Process -Id $p -Force -ErrorAction SilentlyContinue } catch {}
|
||||
}
|
||||
Start-Sleep -Milliseconds 1200
|
||||
$gone = $false
|
||||
$waited = 0
|
||||
for ($i = 0; $i -lt 80; $i++) {
|
||||
$alive = 0
|
||||
foreach ($p in @(__PIDS__)) {
|
||||
if (Get-Process -Id $p -ErrorAction SilentlyContinue) { $alive++ }
|
||||
}
|
||||
if ($alive -eq 0) { $gone = $true; break }
|
||||
Start-Sleep -Milliseconds 250
|
||||
$waited += 250
|
||||
}
|
||||
Write-UpdateLog ("old processes stopped=" + $gone + " after " + $waited + " ms")
|
||||
Start-Sleep -Milliseconds 1500
|
||||
|
||||
$staged = $dst + ".update"
|
||||
$backup = $dst + ".bak"
|
||||
@@ -182,8 +255,9 @@ for ($i = 0; $i -lt 30; $i++) {
|
||||
try {
|
||||
Copy-Item -LiteralPath $src -Destination $staged -Force -ErrorAction Stop
|
||||
if ($expected) {
|
||||
$actual = (Get-FileHash -LiteralPath $staged -Algorithm SHA256).Hash
|
||||
if ($actual -ne $expected) { throw "SHA256 mismatch" }
|
||||
# 用 .NET 而不是 Get-FileHash,兼容没有 PowerShell 4.0 的老系统
|
||||
$actual = Get-Sha256 $staged
|
||||
if ($actual -ne $expected.ToLower()) { throw "SHA256 mismatch" }
|
||||
}
|
||||
$verified = $true
|
||||
Write-UpdateLog "staged copy verified"
|
||||
@@ -548,6 +622,7 @@ class UpdateDialog(QDialog):
|
||||
],
|
||||
creationflags=CREATE_NO_WINDOW,
|
||||
close_fds=True,
|
||||
env=clean_env(),
|
||||
stdin=subprocess.DEVNULL,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
@@ -576,6 +651,7 @@ class UpdateDialog(QDialog):
|
||||
cwd=os.path.dirname(path),
|
||||
creationflags=CREATE_NO_WINDOW,
|
||||
close_fds=True,
|
||||
env=clean_env(),
|
||||
stdin=subprocess.DEVNULL,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
|
||||
+1
-1
@@ -2,6 +2,6 @@
|
||||
|
||||
APP_NAME = "网易云播放器"
|
||||
APP_VERSION = "1.2.7"
|
||||
BUILD_DATE = "2026-10-31"
|
||||
BUILD_DATE = "2026-11-01"
|
||||
UPDATE_ENDPOINT = "https://music.yuncishu.xyz/api/app/update"
|
||||
DOWNLOAD_PAGE = "https://music.yuncishu.xyz/download/"
|
||||
Reference in new issue
Block a user