$fallback7z = Join-Path (Get-Location) "\7z\7zr.exe"; $useragent = "mpv-win-updater" function Get-7z { $7z_command = Get-Command -CommandType Application -ErrorAction Ignore 7z.exe | Select-Object -Last 1 if ($7z_command) { return $7z_command.Source } $7zdir = Get-ItemPropertyValue -ErrorAction Ignore "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\7-Zip" "InstallLocation" if ($7zdir -and (Test-Path (Join-Path $7zdir "7z.exe"))) { return Join-Path $7zdir "7z.exe" } if (Test-Path $fallback7z) { return $fallback7z } return $null } function Check-7z { if (-not (Get-7z)) { $null = New-Item -ItemType Directory -Force (Split-Path $fallback7z) $download_file = $fallback7z Write-Host "Downloading 7zr.exe" -ForegroundColor Green Invoke-WebRequest -Uri "https://www.7-zip.org/a/7zr.exe" -UserAgent $useragent -OutFile $download_file } else { Write-Host "7z already exist. Skipped download" -ForegroundColor Green } } function Check-PowershellVersion { $version = $PSVersionTable.PSVersion.Major Write-Host "Checking Windows PowerShell version -- $version" -ForegroundColor Green if ($version -le 2) { Write-Host "Using Windows PowerShell $version is unsupported. Upgrade your Windows PowerShell." -ForegroundColor Red throw } } function Check-Ytplugin { $ytdlp = Get-ChildItem "yt-dlp*.exe" -ErrorAction Ignore $youtubedl = Get-ChildItem "youtube-dl.exe" -ErrorAction Ignore if ($ytdlp) { return $ytdlp.ToString() } elseif ($youtubedl) { return $youtubedl.ToString() } else { return $null } } function Check-Ytplugin-In-System { $ytp = Get-Command -CommandType Application -ErrorAction Ignore yt-dlp.exe | Select-Object -Last 1 if (-not $ytp) { $ytp = Get-Command -CommandType Application -ErrorAction Ignore youtube-dl.exe | Select-Object -Last 1 } return [bool]($ytp -and ((Split-Path $ytp.Source) -ne (Get-Location))) } function Check-Mpv { $mpv = (Get-Location).Path + "\mpv.exe" $is_exist = Test-Path $mpv return $is_exist } function Download-Archive ($filename, $link) { Write-Host "Downloading" $filename -ForegroundColor Green Invoke-WebRequest -Uri $link -UserAgent $useragent -OutFile $filename } function Get-GitHubToken { $file = "settings.xml" if (Test-Path $file) { $filePath = (Resolve-Path $file).Path [xml]$doc = Get-Content $filePath $settings = $doc.SelectSingleNode("/settings") if ($settings) { $githubtoken = $settings.SelectSingleNode("githubtoken") } if ($settings -and ($null -eq $githubtoken)) { $newNode = $doc.CreateElement("githubtoken") $newNode.AppendChild($doc.CreateTextNode("unset")) | out-null $settings.AppendChild($newNode) | out-null $doc.Save($filePath) $githubtoken = $newNode } if ($settings -and ($null -ne $githubtoken)) { $token = ([string]$githubtoken.InnerText).Trim() if (-not [string]::IsNullOrWhiteSpace($token) -and (-not [string]::Equals($token, "unset", [System.StringComparison]::OrdinalIgnoreCase))) { return $token } } } $token = ([string]$env:GH_TOKEN).Trim() if (-not [string]::IsNullOrWhiteSpace($token)) { return $token } $token = ([string]$env:GITHUB_TOKEN).Trim() if (-not [string]::IsNullOrWhiteSpace($token)) { return $token } return $null } function Invoke-GitHubApi($Uri) { $params = @{ Uri = $Uri MaximumRedirection = 0 ErrorAction = "Ignore" UseBasicParsing = $true UserAgent = $useragent } $token = Get-GitHubToken if (-not [string]::IsNullOrWhiteSpace($token)) { $params.Headers = @{ Authorization = "Bearer $token" } } Invoke-WebRequest @params } function Download-Ytplugin ($plugin, $version) { $link = "" $plugin_exe = "" switch -wildcard ($plugin) { "yt-dlp*" { Write-Host "Downloading $plugin ($version)" -ForegroundColor Green $32bit = "" if (-Not (Test-Path (Join-Path $env:windir "SysWow64"))) { $32bit = "_x86" } $ytdlp_channel = Check-Ytdlp-Channel if ($ytdlp_channel -eq 'stable') { $repo = "https://github.com/yt-dlp/yt-dlp" } elseif ($ytdlp_channel -eq 'nightly') { $repo = "https://github.com/yt-dlp/yt-dlp-nightly-builds" } elseif ($ytdlp_channel -eq 'master') { $repo = "https://github.com/yt-dlp/yt-dlp-master-builds" } $link = -join($repo, "/releases/download/", $version, "/", $plugin, $32bit, ".exe") $plugin_exe = -join($plugin, $32bit, ".exe") } "youtube-dl" { Write-Host "Downloading $plugin ($version)" -ForegroundColor Green $link = -join("https://yt-dl.org/downloads/", $version, "/youtube-dl.exe") $plugin_exe = "youtube-dl.exe" } } Invoke-WebRequest -Uri $link -UserAgent $useragent -OutFile $plugin_exe } function Extract-Archive ($file) { $7z = Get-7z Write-Host "Extracting" $file -ForegroundColor Green & $7z x -y $file } function Get-Latest-Mpv($Arch) { $filename = "" $download_link = "" $api_gh = "https://api.github.com/repos/zhongfly/mpv-winbuild/releases/latest" $json = Invoke-GitHubApi $api_gh | ConvertFrom-Json $filename = $json.assets | where { $_.name -Match "mpv-$Arch-[0-9]{8}" } | Select-Object -ExpandProperty name $download_link = $json.assets | where { $_.name -Match "mpv-$Arch-[0-9]{8}" } | Select-Object -ExpandProperty browser_download_url if ($filename -is [array]) { return $filename[0], $download_link[0] } else { return $filename, $download_link } } function Get-Latest-Ytplugin ($plugin) { switch -wildcard ($plugin) { "yt-dlp*" { $ytdlp_channel = Check-Ytdlp-Channel if ($ytdlp_channel -eq 'stable') { $repo = "https://github.com/yt-dlp/yt-dlp" } elseif ($ytdlp_channel -eq 'nightly') { $repo = "https://github.com/yt-dlp/yt-dlp-nightly-builds" } elseif ($ytdlp_channel -eq 'master') { $repo = "https://github.com/yt-dlp/yt-dlp-master-builds" } $link = -join($repo, "/releases.atom") Write-Host "Fetching RSS feed for yt-dlp $ytdlp_channel" -ForegroundColor Green $resp = [xml](Invoke-WebRequest $link -MaximumRedirection 0 -ErrorAction Ignore -UseBasicParsing).Content $link = $resp.feed.entry[0].link.href $version = $link.split("/")[-1] return $version } "youtube-dl" { $link = "https://yt-dl.org/downloads/latest/youtube-dl.exe" Write-Host "Fetching RSS feed for youtube-dl" -ForegroundColor Green $resp = Invoke-WebRequest $link -MaximumRedirection 0 -ErrorAction Ignore -UseBasicParsing $redirect_link = $resp.Headers.Location $version = $redirect_link.split("/")[4] return $version } } } function Get-Latest-FFmpeg ($Arch) { $api_gh = "https://api.github.com/repos/zhongfly/mpv-winbuild/releases/latest" $json = Invoke-GitHubApi $api_gh | ConvertFrom-Json $filename = $json.assets | where { $_.name -Match "ffmpeg-$Arch-git-" } | Select-Object -ExpandProperty name $download_link = $json.assets | where { $_.name -Match "ffmpeg-$Arch-git-" } | Select-Object -ExpandProperty browser_download_url if ($filename -is [array]) { return $filename[0], $download_link[0] } else { return $filename, $download_link } } function Get-Arch { # Reference: http://superuser.com/a/891443 $FilePath = [System.IO.Path]::Combine((Get-Location).Path, 'mpv.exe') [int32]$MACHINE_OFFSET = 4 [int32]$PE_POINTER_OFFSET = 60 [byte[]]$data = New-Object -TypeName System.Byte[] -ArgumentList 4096 $stream = New-Object -TypeName System.IO.FileStream -ArgumentList ($FilePath, 'Open', 'Read') $stream.Read($data, 0, 4096) | Out-Null # DOS header is 64 bytes, last element, long (4 bytes) is the address of the PE header [int32]$PE_HEADER_ADDR = [System.BitConverter]::ToInt32($data, $PE_POINTER_OFFSET) [int32]$machineUint = [System.BitConverter]::ToUInt16($data, $PE_HEADER_ADDR + $MACHINE_OFFSET) $result = "" | select FilePath, FileType $result.FilePath = $FilePath switch ($machineUint) { 0 { $result.FileType = 'Native' } 0x014c { $result.FileType = 'i686' } # 32bit 0x0200 { $result.FileType = 'Itanium' } 0x8664 { $result.FileType = 'x86_64' } # 64bit } $stream.Close() $result } function Get-RegexGroupValue($Text, [string[]]$Patterns, $GroupName) { if ([string]::IsNullOrEmpty([string]$Text)) { return $null } foreach ($pattern in $Patterns) { $match = [regex]::Match([string]$Text, $pattern) if ($match.Success) { $group = $match.Groups[$GroupName] if ($group -and -not [string]::IsNullOrEmpty($group.Value)) { return $group.Value } } } return $null } function Test-CommitEquivalent($Left, $Right) { if ([string]::IsNullOrEmpty($Left) -or [string]::IsNullOrEmpty($Right)) { return $false } $shorter = [string]$Left $longer = [string]$Right if ($shorter.Length -gt $longer.Length) { $shorter = [string]$Right $longer = [string]$Left } return $longer.StartsWith($shorter, [System.StringComparison]::OrdinalIgnoreCase) } function ExtractGitFromFile { $stripped = .\mpv --no-config | select-string "mpv" | select-object -First 1 $patterns = @( "-g(?[0-9A-Fa-f]{7,40})(?=[^0-9A-Fa-f]|$)" ) return Get-RegexGroupValue $stripped $patterns "commit" } function ExtractGitFromURL($filename) { $patterns = @( "-git-(?[0-9A-Fa-f]{7,40})(?=[^0-9A-Fa-f]|$)" ) return Get-RegexGroupValue $filename $patterns "commit" } function ExtractDateFromFile { $date = (Get-Item ./mpv.exe).LastWriteTimeUtc $day = $date.Day.ToString("00") $month = $date.Month.ToString("00") $year = $date.Year.ToString("0000") return "$year$month$day" } function ExtractDateFromURL($filename) { $patterns = @( "-(?[0-9]{8})-git-[0-9A-Fa-f]{7,40}(?=[^0-9A-Fa-f]|$)" ) return Get-RegexGroupValue $filename $patterns "date" } function Ensure-Deno([string]$Context = "update") { $deno_exe = Join-Path (Get-Location) "deno.exe" if (Test-Path $deno_exe) { # Only fetch remote tag when Deno exists and we need to compare $remote_name = (Invoke-WebRequest "https://dl.deno.land/release-latest.txt" -UseBasicParsing -UserAgent $useragent).Content.Trim() try { $current_version = (& $deno_exe --version | Select-String "deno" | Select-Object -First 1).ToString() $pattern = "deno\s+(?[0-9a-zA-Z\.-]+)" $m = [Regex]::Match($current_version, $pattern) if ($m.Success) { $current_tag = $m.Groups['ver'].Value $latest_norm = $remote_name.TrimStart('v') if ($current_tag -eq $latest_norm) { Write-Host "You are already using latest Deno -- $remote_name" -ForegroundColor Green return } else { Write-Host "Newer Deno build available" -ForegroundColor Green } } } catch { Write-Host "Error checking current Deno version: $($_.Exception.Message)" -ForegroundColor Yellow } $upgradePrompt = "Upgrade local Deno to latest stable now? [Y/n] (default=y)" $upgradeResp = Read-KeyOrTimeout $upgradePrompt "Y" Write-Host "" if ($upgradeResp -eq 'Y') { & $deno_exe upgrade } return } # No local deno: only offer install during initial yt-dlp install flow if ($Context -ne 'install') { return } # Deno provides only x86_64 builds for Windows. Skip on 32-bit systems. if (-Not (Test-Path (Join-Path $env:windir "SysWow64"))) { Write-Host "Deno isn't available for 32-bit Windows (x86). Skipping." -ForegroundColor Yellow return } # Fetch remote tag only if we are going to download Write-Host "Deno is optional, but recommended for yt-dlp." -ForegroundColor Yellow Write-Host "yt-dlp uses external JS runtimes (EJS) to solve YouTube challenges; Deno is the default recommended runtime." -ForegroundColor Yellow Write-Host "You may skip this and configure Node, Bun, or QuickJS later (see: https://github.com/yt-dlp/yt-dlp/wiki/EJS)." -ForegroundColor Yellow Write-Host "" Write-Host "Deno doesn't exist. " -ForegroundColor Green -NoNewline $resp = Read-KeyOrTimeout "Proceed with downloading Deno now? [Y/n] (default=y)" "Y" Write-Host "" if ($resp -ne 'Y') { return } $remote_name = (Invoke-WebRequest "https://dl.deno.land/release-latest.txt" -UseBasicParsing -UserAgent $useragent).Content.Trim() $download_link = "https://dl.deno.land/release/$remote_name/deno-x86_64-pc-windows-msvc.zip" $archive = "deno-x86_64-pc-windows-msvc.zip" Write-Host "Downloading Deno (stable) $remote_name" -ForegroundColor Green Download-Archive $archive $download_link Check-7z Extract-Archive $archive Check-Autodelete $archive } function Test-Admin { $user = [Security.Principal.WindowsIdentity]::GetCurrent(); (New-Object Security.Principal.WindowsPrincipal $user).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator) } function Create-XML{ @" unset unset unset unset unset unset "@ | Set-Content "settings.xml" -Encoding UTF8 } function Check-Arch($arch) { $get_arch = "" $file = "settings.xml" if (-not (Test-Path $file)) { Create-XML } [xml]$doc = Get-Content $file if ($doc.settings.arch -eq "unset") { if ($arch -eq "i686") { $get_arch = "i686" } else { $result = Read-KeyOrTimeout "Choose variant for 64bit builds: x86_64 or x86_64-v3 (for cpu with AVX2 support) [1=x86_64 / 2=x86_64-v3 (default=1)" "D1" Write-Host "" if ($result -eq 'D1') { $get_arch = "x86_64" } elseif ($result -eq 'D2') { $get_arch = "x86_64-v3" } else { throw "Please enter valid input key." } } $doc.settings.arch = $get_arch $doc.Save($file) } else { $get_arch = $doc.settings.arch } return $get_arch } function Check-Autodelete($archive) { $autodelete = "" $file = "settings.xml" if (-not (Test-Path $file)) { exit } [xml]$doc = Get-Content $file if ($doc.settings.autodelete -eq "unset") { $result = Read-KeyOrTimeout "Delete archives after extract? [Y/n] (default=Y)" "Y" Write-Host "" if ($result -eq 'Y') { $autodelete = "true" } elseif ($result -eq 'N') { $autodelete = "false" } else { throw "Please enter valid input key." } $doc.settings.autodelete = $autodelete $doc.Save($file) } if ($doc.settings.autodelete -eq "true") { if (Test-Path $archive) { Remove-Item -Force $archive } } } function Check-GetFFmpeg() { $get_ffmpeg = "" $file = "settings.xml" if (-not (Test-Path $file)) { exit } [xml]$doc = Get-Content $file if ($doc.settings.getffmpeg -eq "unset") { Write-Host "FFmpeg doesn't exist. " -ForegroundColor Green -NoNewline $result = Read-KeyOrTimeout "Proceed with downloading? [Y/n] (default=n)" "N" Write-Host "" if ($result -eq 'Y') { $get_ffmpeg = "true" } elseif ($result -eq 'N') { $get_ffmpeg = "false" } else { throw "Please enter valid input key." } $doc.settings.getffmpeg = $get_ffmpeg $doc.Save($file) } else { $get_ffmpeg = $doc.settings.getffmpeg } return $get_ffmpeg } function Check-GetYTDL() { $get_ytdl = "" $file = "settings.xml" if (-not (Test-Path $file)) { exit } [xml]$doc = Get-Content $file if ($null -eq $doc.settings.getytdl) { $yt = Check-Ytplugin if ($yt -eq $null){ $get_ytdl = "unset" } elseif ((Get-Item $yt).BaseName -Match "yt-dlp*") { $get_ytdl = "ytdlp" } else { $get_ytdl = "youtubedl" } $newNode = $doc.CreateElement("getytdl") $newNode.AppendChild($doc.CreateTextNode($get_ytdl)) | out-null $doc.settings.appendchild($newNode) | out-null $doc.Save($file) } else { $get_ytdl = $doc.settings.getytdl } if ($get_ytdl -eq "unset") { $result = Read-KeyOrTimeout "Download ytdlp or youtubedl? [1=ytdlp/2=youtubedl/N] (default=1)" "D1" Write-Host "" if ($result -eq 'D1') { $get_ytdl = "ytdlp" } elseif ($result -eq 'D2') { $get_ytdl = "youtubedl" } elseif ($result -eq 'N') { $get_ytdl = "false" } else { throw "Please enter valid input key." } $doc.settings.getytdl = $get_ytdl $doc.Save($file) } return $get_ytdl } function Check-Ytdlp-Channel() { $ytdlp_channel = "" $file = "settings.xml" if (-not (Test-Path $file)) { exit } [xml]$doc = Get-Content $file if ($null -eq $doc.settings.ytdlpchannel) { $newNode = $doc.CreateElement("ytdlpchannel") $newNode.AppendChild($doc.CreateTextNode("unset")) | out-null $doc.settings.appendchild($newNode) | out-null } if ($doc.settings.ytdlpchannel -eq "unset") { $result = Read-KeyOrTimeout "Which update channel to update yt-dlp to? [1=stable/2=nightly/3=master] (default=1)" "D1" Write-Host "" if ($result -eq 'D1') { $ytdlp_channel = "stable" } elseif ($result -eq 'D2') { $ytdlp_channel = "nightly" } elseif ($result -eq 'D3') { $ytdlp_channel = "master" } else { throw "Please enter valid input key." } $doc.settings.ytdlpchannel = $ytdlp_channel $doc.Save($file) } else { $ytdlp_channel = $doc.settings.ytdlpchannel } return $ytdlp_channel } function Upgrade-Mpv { $need_download = $false $remoteName = "" $download_link = "" $arch = "" if (Check-Mpv) { $file_arch = (Get-Arch).FileType $arch = Check-Arch $file_arch $remoteName, $download_link = Get-Latest-Mpv $arch $localgit = ExtractGitFromFile $localdate = ExtractDateFromFile $remotegit = ExtractGitFromURL $remoteName $remotedate = ExtractDateFromURL $remoteName if ([string]::IsNullOrEmpty($localgit) -or [string]::IsNullOrEmpty($remotegit) -or [string]::IsNullOrEmpty($localdate) -or [string]::IsNullOrEmpty($remotedate)) { Write-Host "Unable to compare local and remote mpv build metadata. Downloading latest build." -ForegroundColor Yellow $need_download = $true } elseif (Test-CommitEquivalent $localgit $remotegit) { if ($localdate -eq $remotedate) { Write-Host "You are already using latest mpv build -- $remoteName" -ForegroundColor Green $need_download = $false } else { Write-Host "Newer mpv build available" -ForegroundColor Green $need_download = $true } } else { Write-Host "Newer mpv build available" -ForegroundColor Green $need_download = $true } } else { Write-Host "mpv doesn't exist. " -ForegroundColor Green -NoNewline $result = Read-KeyOrTimeout "Proceed with downloading? [Y/n] (default=y)" "Y" Write-Host "" if ($result -eq 'Y') { $need_download = $true if (Test-Path (Join-Path $env:windir "SysWow64")) { Write-Host "Detecting System Type is 64-bit" -ForegroundColor Green $original_arch = "x86_64" } else { Write-Host "Detecting System Type is 32-bit" -ForegroundColor Green $original_arch = "i686" } $arch = Check-Arch $original_arch $remoteName, $download_link = Get-Latest-Mpv $arch } elseif ($result -eq 'N') { $need_download = $false } else { throw "Please enter valid input key." } } if ($need_download) { Download-Archive $remoteName $download_link Check-7z Extract-Archive $remoteName } Check-Autodelete $remoteName } function Upgrade-Ytplugin { if (Check-Ytplugin-In-System) { Write-Host "yt-dlp.exe or youtube-dl.exe already exists in your system, skip the update check." -ForegroundColor Green return } $yt = Check-Ytplugin if ($yt) { $latest_release = Get-Latest-Ytplugin((Get-Item $yt).BaseName) if ((& $yt --version) -match ($latest_release)) { Write-Host "You are already using latest" (Get-Item $yt).BaseName "-- $latest_release" -ForegroundColor Green if ((Get-Item $yt).BaseName -Match "yt-dlp*") { # Even if yt-dlp is up-to-date, ensure Deno runtime is updated Ensure-Deno "update" } } else { Write-Host "Newer" (Get-Item $yt).BaseName "build available" -ForegroundColor Green if ((Get-Item $yt).BaseName -Match "yt-dlp*") { $ytdlp_channel = Check-Ytdlp-Channel & $yt --update-to $ytdlp_channel Ensure-Deno "update" } else { & $yt --update } } } else { Write-Host "ytdlp or youtube-dl doesn't exist. " -ForegroundColor Green -NoNewline # Use persisted setting to decide which plugin to install $ytdl = Check-GetYTDL if ($ytdl -eq 'ytdlp') { $latest_release = Get-Latest-Ytplugin "yt-dlp" Download-Ytplugin "yt-dlp" $latest_release Ensure-Deno "install" } elseif ($ytdl -eq 'youtubedl') { $latest_release = Get-Latest-Ytplugin "youtube-dl" Download-Ytplugin "youtube-dl" $latest_release } elseif ($ytdl -ne 'false') { throw "Please enter valid input key." } } } function Upgrade-FFmpeg { $get_ffmpeg = Check-GetFFmpeg if ($get_ffmpeg -eq "false") { return } if (Test-Path (Join-Path $env:windir "SysWow64")) { $original_arch = "x86_64" $arch = Check-Arch $original_arch } else { $arch = "i686" } $need_download = $false $remote_name, $download_link = Get-Latest-FFmpeg $arch $ffmpeg = (Get-Location).Path + "\ffmpeg.exe" $ffmpeg_exist = Test-Path $ffmpeg if ($ffmpeg_exist) { $ffmpeg_file = .\ffmpeg -version | select-string "ffmpeg" | select-object -First 1 $file_patterns = @( "git-[0-9]{4}-[0-9]{2}-[0-9]{2}-(?[0-9A-Fa-f]{7,40})(?=[^0-9A-Fa-f]|$)", "N-\d+-g(?[0-9A-Fa-f]{7,40})(?=[^0-9A-Fa-f]|$)" ) $url_patterns = @( "-git-(?[0-9A-Fa-f]{7,40})(?=[^0-9A-Fa-f]|$)" ) $local_git = Get-RegexGroupValue $ffmpeg_file $file_patterns "commit" $remote_git = Get-RegexGroupValue $remote_name $url_patterns "commit" if ([string]::IsNullOrEmpty($local_git) -or [string]::IsNullOrEmpty($remote_git)) { Write-Host "Unable to compare local and remote ffmpeg build metadata. Downloading latest build." -ForegroundColor Yellow $need_download = $true } elseif (Test-CommitEquivalent $local_git $remote_git) { Write-Host "You are already using latest ffmpeg build -- $remote_name" -ForegroundColor Green $need_download = $false } else { Write-Host "Newer ffmpeg build available" -ForegroundColor Green $need_download = $true } } else { $need_download = $true } if ($need_download) { Download-Archive $remote_name $download_link Check-7z Extract-Archive $remote_name } Check-Autodelete $remote_name } function Read-KeyOrTimeout ($prompt, $key){ $seconds = 9 $startTime = Get-Date $timeOut = New-TimeSpan -Seconds $seconds Write-Host "$prompt " -ForegroundColor Green # Basic progress bar [Console]::CursorLeft = 0 [Console]::Write("[") [Console]::CursorLeft = $seconds + 2 [Console]::Write("]") [Console]::CursorLeft = 1 while (-not [System.Console]::KeyAvailable) { $currentTime = Get-Date Start-Sleep -s 1 Write-Host "#" -ForegroundColor Green -NoNewline if ($currentTime -gt $startTime + $timeOut) { Break } } if ([System.Console]::KeyAvailable) { $response = [System.Console]::ReadKey($true).Key } else { $response = $key } return $response.ToString() } # # Main script entry point # if (Test-Admin) { Write-Host "Running script with administrator privileges" -ForegroundColor Yellow } else { Write-Host "Running script without administrator privileges" -ForegroundColor Red } try { Check-PowershellVersion # Sourceforge only support TLS 1.2 [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $global:progressPreference = 'silentlyContinue' Upgrade-Mpv Upgrade-Ytplugin Upgrade-FFmpeg Write-Host "Operation completed" -ForegroundColor Magenta } catch [System.Exception] { Write-Host $_.Exception.Message -ForegroundColor Red exit 1 }