param ( [boolean]$dbg, [boolean]$upd, [boolean]$rem, [boolean]$doupd, [string]$variant ) if ($variant -eq "lite") { $hash_prop = "hashes-lite" } else { $hash_prop = "hashes" } $update_url = "https://mediatools.alamios.es/app" $install_dir = [Environment]::GetFolderPath('LocalApplicationData') $app_package = "alamios" $app_name = "MediaTools" $app_dir = "$install_dir\$app_package\$app_name" $meta_file = "metadata.json" $launcher_file = "launcher.ps1" $icon_file = "icon.dll" $main_file = "src\main.ps1" $temp_launcher = "$($env:TEMP)\$app_name-*.ps1" $shortcut_dir = "$([Environment]::GetFolderPath('StartMenu'))\Programs\$app_package" $launcher_shortcut = "$app_name.lnk" $uninstall_shortcut = "Uninstall $app_name.lnk" $update_interval = -1 # 1day $msg = @{ install="Instalando, por favor, espere..." update="Actualizando, por favor, espere..." remove="Eliminando, por favor, espere..." retry="Pulse enter para reintentar" error_remove="Error al desinstalar. Compruebe que no tiene abierto algún archivo de la aplicación." } function install_app { Write-Progress -Activity $msg.install -Status " " New-Item -Path $app_dir -ItemType "directory" -ErrorAction Ignore Invoke-WebRequest -Uri "$update_url/$meta_file" -OutFile "$app_dir\$meta_file" $hashes = ((Get-Content "$app_dir\$meta_file") | ConvertFrom-Json).$hash_prop $len = ($hashes.PsObject.Properties | Measure-Object).Count $i = 1 foreach ($item in $hashes.PsObject.Properties) { Write-Progress -Activity $msg.install -Status "Descargando $i/$len - $([math]::Round(($i/$len)*100))%" if ($item.name -like "*/*") { New-Item -Force -Path $app_dir -Name ($item.name.SubString(0, $item.name.LastIndexOf('/'))) -ItemType "directory" } Start-BitsTransfer -Source "$update_url/$($item.name)" -Destination "$app_dir\$($item.name)" $i++ } $meta = (Invoke-RestMethod -Uri "$update_url/$meta_file") save_metadata create_shortcut } function update_app { Write-Progress -Activity $msg.update -Status " " $meta = (Invoke-RestMethod -Uri "$update_url/$meta_file") $hashes = $meta.$hash_prop $prev_meta = ((Get-Content "$app_dir\$meta_file" -ErrorAction Ignore) | ConvertFrom-Json) $prev_hashes = $prev_meta.hashes $download_req = @() if ($prev_hashes) { $i = 1 $len = ($prev_hashes.PsObject.Properties | Measure-Object).Count foreach ($item in $prev_hashes.PsObject.Properties) { Write-Progress -Activity $msg.update -Status "Comprobando $i/$len - $([math]::Round(($i/$len)*100))%" if (-not ($item.name -in $hashes.PSobject.Properties.Name)) { Remove-Item "$app_dir\$($item.name)" -ErrorAction Ignore } $i++ } $i = 1 $len = ($hashes.PsObject.Properties | Measure-Object).Count foreach ($item in $hashes.PsObject.Properties) { Write-Progress -Activity $msg.update -Status "Comprobando $i/$len - $([math]::Round(($i/$len)*100))%" if (-not (Test-Path -Path "$app_dir\$($item.name)") -or -not (hash_match -path "$app_dir\$($item.name)" -prev_hash $prev_hashes.$($item.name) -new_hash $item.value)) { $download_req += $item.name } $i++ } } else { Remove-Item -path ("$app_dir\*") -Recurse -Force -ErrorAction Ignore $download_req = $hashes.PsObject.Properties.Name } $i = 1 foreach ($item in $download_req) { $item_path = "$app_dir\$($item)" Write-Progress -Activity $msg.update -Status "Descargando $i/$($download_req.Length) - $([math]::Round(($i/$download_req.Length)*100))%" if ($item -like "*/*") { New-Item -Force -Path $app_dir -Name ($item.SubString(0, $item.LastIndexOf('/'))) -ItemType "directory" } Start-BitsTransfer -Source "$update_url/$($item)" -Destination $item_path $i++ } save_metadata # Remove empty folders Get-ChildItem $app_dir -Recurse -Force -Directory | Sort-Object -Property FullName -Descending | Where-Object { $($_ | Get-ChildItem -Force | Select-Object -First 1).Count -eq 0 } | Remove-Item -Verbose # Remove updater Remove-Item (Get-ChildItem $temp_launcher) -ErrorAction Ignore create_shortcut } function hash_match($path, $prev_hash, $new_hash) { if ($path.EndsWith(".ps1")) { return $new_hash -eq (Get-FileHash $path).Hash } else { return $prev_hash -eq $new_hash } } function launch_update { $tempPs = $temp_launcher.Replace("*", (Get-Date).ToFileTime()) Invoke-WebRequest -Uri "$update_url/$launcher_file" -OutFile $tempPs Start-Process powershell -argument "$tempPs -doupd 1 -variant $variant" } function req_update_version { $tempVer = (Invoke-RestMethod -Uri "$update_url/$meta_file").version $version = $meta.version $tv = [int[]]($tempVer.split("\.")) $v = [int[]]($version.split("\.")) return $tv[0] -gt $v[0] -or ($tv[0] -eq $v[0] -and $tv[1] -gt $v[1]) -or ($tv[0] -eq $v[0] -and $tv[1] -eq $v[1] -and $tv[2] -gt $v[2]) } function req_update_time { return ([datetime]::FromFileTime($meta.lastcheck)) -lt ((Get-Date).AddDays($update_interval).Date) } function req_update_variant { return $meta.variant -ne $variant } function relaunch_update { $meta = load_metadata if ((([int[]]($meta.version.split("\.")))[0] -lt 9) -and (-not $variant)) { Add-Type -AssemblyName PresentationFramework $continue = [System.Windows.MessageBox]::Show("La nueva versión de MediaTools incluye Whisper, que ocupa 7GB extra. Pulsa Sí para continuar la actualización. Pulsa No para instalar la versión Lite, más reducida.", "Nueva versión", 'YesNo', "Question"); if ($continue -eq 'Yes') { $variant = "full" } else { $variant = "lite" } $tempPs = $temp_launcher.Replace("*", (Get-Date).ToFileTime()) Invoke-WebRequest -Uri "$update_url/$launcher_file" -OutFile tempPs Start-Process powershell -argument "$tempPs -doupd 1 -variant $variant" return $true } return $false } function uninstall_app { Add-Type -AssemblyName PresentationFramework $continue = [System.Windows.MessageBox]::Show("Desinstalando $app_name. Esta acción eliminará la aplicación completamente de su sistema. ¿Continuar?", "Desinstalación", 'YesNo', "Warning"); if ($continue -eq 'Yes') { Write-host $msg.remove try { Remove-Item -Recurse -Force "$app_dir\*" -ErrorAction Stop Remove-Item -Recurse -Force $shortcut_dir -ErrorAction Ignore } catch { Write-host $msg.error_remove -ForegroundColor Red Read-Host $msg.retry uninstall_app } } } function load_metadata { if (Test-Path -Path "$app_dir\$meta_file") { return (Get-Content "$app_dir\$meta_file") | ConvertFrom-Json } return $false } function save_metadata { $meta.variant = $variant $meta.lastcheck = (Get-Date).ToFileTimeUTC() [IO.File]::WriteAllLines("$app_dir\$meta_file", ($meta | ConvertTo-Json -Depth 100)) return $true } function create_shortcut { New-Item -Path $shortcut_dir -ItemType "directory" -ErrorAction Ignore $WshShell = New-Object -comObject WScript.Shell $main_sc = $WshShell.CreateShortcut("$shortcut_dir\$launcher_shortcut") $main_sc.TargetPath = "powershell.exe" $main_sc.WorkingDirectory = "$app_dir" $main_sc.Arguments = "-ExecutionPolicy bypass -Command `"./launcher.ps1 -variant $variant`"" $main_sc.IconLocation = "$app_dir\$icon_file, 0" $main_sc.Save() $uninstall_sc = $WshShell.CreateShortcut("$shortcut_dir\$uninstall_shortcut") $uninstall_sc.TargetPath = "powershell.exe" $uninstall_sc.WorkingDirectory = "$app_dir" $uninstall_sc.Arguments = "-ExecutionPolicy bypass -Command `"./launcher.ps1 -rem 1`"" $uninstall_sc.IconLocation = "$app_dir\$icon_file, 1" $uninstall_sc.Save() } function run_app($dbg) { $root = if ($dbg) { "$PSScriptRoot" } else { "$app_dir" } powershell -windowstyle Hidden -file "$root\$main_file" -variant $variant } if ($dbg) { run_app -dbg 1 } elseif (-not (Test-Path -Path "$app_dir\$launcher_file")) { install_app run_app } elseif ($doupd) { if (-not (relaunch_update)) { update_app run_app } } elseif ($rem) { uninstall_app } else { $meta = load_metadata if (-not $meta -or (req_update_variant) -or (($upd -or (req_update_time)) -and (req_update_version) -and (save_metadata))) { launch_update } else { run_app } }