2026-03-26 03:26:37 -07:00
# Requires -Version 5.1
# Requires -RunAsAdministrator
[ CmdletBinding ( ) ]
param (
[ string ] $InstallRoot ,
[ string ] $IconPath ,
[ switch ] $KeepExistingProtocolKeys
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
function Resolve-ExistingFile {
param (
[ Parameter ( Mandatory = $true ) ]
[ string ] $BasePath ,
[ Parameter ( Mandatory = $true ) ]
[ string ] $FileName
)
$resolvedPath = Join-Path -Path $BasePath -ChildPath $FileName
if ( -not ( Test-Path -LiteralPath $resolvedPath -PathType Leaf ) ) {
throw " Required file not found: $resolvedPath `n InstallRoot must point at the extracted mpv-handler folder that contains config.toml, mpv-handler.exe, and mpv-handler-debug.exe. "
}
return ( Resolve-Path -LiteralPath $resolvedPath ) . Path
}
function Get-UsageExample {
return @"
E x a m p l e u s a g e :
p o w e r s h e l l - E x e c u t i o n P o l i c y B y p a s s - F i l e . \ s c r i p t s \ i n s t a l l - m p v - h a n d l e r . p s 1 - I n s t a l l R o o t ' C : \ p a t h \ t o \ m p v - h a n d l e r '
O r f r o m a n e l e v a t e d P o w e r S h e l l s e s s i o n :
& ' C : \ F o r g e j o \ A P I - M e d i a P l a y e r \ s c r i p t s \ i n s t a l l - m p v - h a n d l e r . p s 1 ' - I n s t a l l R o o t ' C : \ p a t h \ t o \ m p v - h a n d l e r '
I f c o n f i g . t o m l , m p v - h a n d l e r . e x e , a n d m p v - h a n d l e r - d e b u g . e x e a r e i n t h e s a m e f o l d e r a s t h i s s c r i p t ,
y o u c a n r u n i t w i t h o u t - I n s t a l l R o o t .
"@
}
function Test-InstallRootContents {
param (
[ string ] $CandidatePath
)
if ( -not $CandidatePath ) {
return $false
}
if ( -not ( Test-Path -LiteralPath $CandidatePath -PathType Container ) ) {
return $false
}
return (
( Test-Path -LiteralPath ( Join-Path -Path $CandidatePath -ChildPath 'config.toml' ) -PathType Leaf ) -and
( Test-Path -LiteralPath ( Join-Path -Path $CandidatePath -ChildPath 'mpv-handler.exe' ) -PathType Leaf ) -and
( Test-Path -LiteralPath ( Join-Path -Path $CandidatePath -ChildPath 'mpv-handler-debug.exe' ) -PathType Leaf )
)
}
function Get-DefaultInstallRoot {
if ( Test-InstallRootContents -CandidatePath $PSScriptRoot ) {
return ( Resolve-Path -LiteralPath $PSScriptRoot ) . Path
}
return $null
}
function Assert-InstallRoot {
param (
[ string ] $CandidatePath
)
if ( -not $CandidatePath ) {
$defaultInstallRoot = Get-DefaultInstallRoot
if ( $defaultInstallRoot ) {
return $defaultInstallRoot
}
throw " InstallRoot is required. `n $( Get-UsageExample ) "
}
if ( -not ( Test-Path -LiteralPath $CandidatePath -PathType Container ) ) {
throw " InstallRoot does not exist or is not a folder: $CandidatePath `n $( Get-UsageExample ) "
}
$resolved = ( Resolve-Path -LiteralPath $CandidatePath ) . Path
if ( Test-Path -LiteralPath ( Join-Path -Path $resolved -ChildPath 'package.json' ) -PathType Leaf ) {
throw " InstallRoot appears to be this repo, not the extracted mpv-handler folder: $resolved `n $( Get-UsageExample ) "
}
return $resolved
}
function Get-MpvPathFromConfig {
param (
[ Parameter ( Mandatory = $true ) ]
[ string ] $ConfigPath
)
if ( -not ( Test-Path -LiteralPath $ConfigPath -PathType Leaf ) ) {
return $null
}
$raw = Get-Content -LiteralPath $ConfigPath -Raw
$match = [ regex ] :: Match ( $raw , '(?m)^\s*mpv\s*=\s*"(?<path>[^"]+)"\s*$' )
if ( -not $match . Success ) {
return $null
}
$candidate = $match . Groups [ 'path' ] . Value . Trim ( )
if ( -not $candidate ) {
return $null
}
if ( [ System.IO.Path ] :: IsPathRooted ( $candidate ) -and ( Test-Path -LiteralPath $candidate -PathType Leaf ) ) {
return ( Resolve-Path -LiteralPath $candidate ) . Path
}
try {
$command = Get-Command -Name $candidate -ErrorAction Stop
return $command . Source
} catch {
return $null
}
}
2026-04-18 18:12:17 -07:00
function Resolve-CommandPath {
param (
[ Parameter ( Mandatory = $true ) ]
[ string[] ] $Names
)
foreach ( $name in $Names ) {
try {
$command = Get-Command -Name $name -ErrorAction Stop
if ( $command . Path ) {
return $command . Path
}
if ( $command . Source ) {
return $command . Source
}
} catch {
}
}
return $null
}
2026-03-26 03:26:37 -07:00
function Remove-ProtocolKey {
param (
[ Parameter ( Mandatory = $true ) ]
[ string ] $SchemeName
)
$classesRoot = [ Microsoft.Win32.Registry ] :: ClassesRoot
try {
$classesRoot . DeleteSubKeyTree ( $SchemeName , $false )
} catch {
}
}
function Register-Protocol {
param (
[ Parameter ( Mandatory = $true ) ]
[ string ] $SchemeName ,
[ Parameter ( Mandatory = $true ) ]
[ string ] $Description ,
[ Parameter ( Mandatory = $true ) ]
[ string ] $ContentType ,
[ Parameter ( Mandatory = $true ) ]
[ string ] $HandlerExecutable ,
[ Parameter ( Mandatory = $true ) ]
[ string ] $EffectiveIconPath
)
$classesRoot = [ Microsoft.Win32.Registry ] :: ClassesRoot
$schemeKey = $classesRoot . CreateSubKey ( $SchemeName )
if ( -not $schemeKey ) {
throw " Failed to create registry key for $SchemeName "
}
try {
$schemeKey . SetValue ( '' , $Description , [ Microsoft.Win32.RegistryValueKind ] :: String )
$schemeKey . SetValue ( 'Content Type' , $ContentType , [ Microsoft.Win32.RegistryValueKind ] :: String )
$schemeKey . SetValue ( 'URL Protocol' , '' , [ Microsoft.Win32.RegistryValueKind ] :: String )
$defaultIconKey = $schemeKey . CreateSubKey ( 'DefaultIcon' )
try {
$defaultIconKey . SetValue ( '' , ( '"{0}",1' -f $EffectiveIconPath ) , [ Microsoft.Win32.RegistryValueKind ] :: String )
} finally {
$defaultIconKey . Dispose ( )
}
$commandKey = $schemeKey . CreateSubKey ( 'shell\open\command' )
try {
$commandKey . SetValue ( '' , ( '"{0}" "%1"' -f $HandlerExecutable ) , [ Microsoft.Win32.RegistryValueKind ] :: String )
} finally {
$commandKey . Dispose ( )
}
} finally {
$schemeKey . Dispose ( )
}
}
if ( [ System.Environment ] :: OSVersion . Platform -ne [ System.PlatformID ] :: Win32NT ) {
throw 'This installer is only for Windows.'
}
$installRootPath = Assert-InstallRoot -CandidatePath $InstallRoot
$configPath = Resolve-ExistingFile -BasePath $installRootPath -FileName 'config.toml'
$handlerPath = Resolve-ExistingFile -BasePath $installRootPath -FileName 'mpv-handler.exe'
$handlerDebugPath = Resolve-ExistingFile -BasePath $installRootPath -FileName 'mpv-handler-debug.exe'
$effectiveIconPath = if ( $IconPath ) {
if ( -not ( Test-Path -LiteralPath $IconPath -PathType Leaf ) ) {
throw " IconPath does not exist: $IconPath "
}
( Resolve-Path -LiteralPath $IconPath ) . Path
} else {
2026-04-18 18:12:17 -07:00
$configuredPath = Get-MpvPathFromConfig -ConfigPath $configPath
if ( $configuredPath ) {
$configuredPath
} else {
Resolve-CommandPath -Names @ ( 'mpv.com' , 'mpv.exe' , 'mpv' )
}
2026-03-26 03:26:37 -07:00
}
if ( -not $effectiveIconPath ) {
$effectiveIconPath = $handlerPath
}
if ( -not $KeepExistingProtocolKeys ) {
Remove-ProtocolKey -SchemeName 'mpv'
Remove-ProtocolKey -SchemeName 'mpv-debug'
Remove-ProtocolKey -SchemeName 'mpv-handler'
Remove-ProtocolKey -SchemeName 'mpv-handler-debug'
}
Register-Protocol -SchemeName 'mpv-handler' -Description 'URL:MPV Handler' -ContentType 'application/x-mpv-handler' -HandlerExecutable $handlerPath -EffectiveIconPath $effectiveIconPath
Register-Protocol -SchemeName 'mpv-handler-debug' -Description 'URL:MPV Handler Debug' -ContentType 'application/x-mpv-handler-debug' -HandlerExecutable $handlerDebugPath -EffectiveIconPath $effectiveIconPath
Write-Host 'Successfully installed mpv-handler protocol registration.' -ForegroundColor Green
Write-Host ( 'InstallRoot: {0}' -f $installRootPath )
Write-Host ( 'Handler: {0}' -f $handlerPath )
Write-Host ( 'Debug Handler: {0}' -f $handlerDebugPath )
Write-Host ( 'Icon: {0}' -f $effectiveIconPath )
Write-Host 'You can now test an mpv-handler:// URL from the browser.'