update installation instructions and add mpv handler setup script
This commit is contained in:
+462
-145
@@ -1,155 +1,472 @@
|
||||
[English][readme-en] | [简体中文][readme-zh-hans] | [繁体中文][readme-zh-hant]
|
||||
# mpv-handler setup
|
||||
|
||||
[readme-en]: https://github.com/akiirui/mpv-handler/blob/main/README.md
|
||||
[readme-zh-hans]: https://github.com/akiirui/mpv-handler/blob/main/README.zh-Hans.md
|
||||
[readme-zh-hant]: https://github.com/akiirui/mpv-handler/blob/main/README.zh-Hant.md
|
||||
This folder contains the desktop playback helper assets used by API Media Player.
|
||||
|
||||
# mpv handler
|
||||
## What is in this folder
|
||||
|
||||
A protocol handler for **mpv**, written by Rust.
|
||||
- `setup-mpv-handler.mjs`: cross-platform helper used by `npm run setup:mpv-handler`
|
||||
- `install-mpv-handler.ps1`: Windows protocol registration script
|
||||
- `uninstall-mpv-handler.ps1`: Windows protocol cleanup script
|
||||
- `handler-install.bat` and `handler-uninstall.bat`: thin Windows wrappers for the PowerShell scripts
|
||||
- `config.toml`: template used when the helper needs to create or refresh an `mpv-handler` config
|
||||
- `mpv-handler.exe` and `mpv-handler-debug.exe`: bundled Windows handler binaries
|
||||
|
||||
Use **mpv** and **yt-dlp** to play video and music from the websites.
|
||||
|
||||
Please use it with userscript:
|
||||
|
||||
[![play-with-mpv][badges-play-with-mpv]][greasyfork-play-with-mpv]
|
||||
|
||||
## Breaking changes
|
||||
|
||||
### [v0.4.0][v0.4.0]
|
||||
|
||||
To avoid conflicts with the `mpv://` protocol provided by mpv.
|
||||
|
||||
> mpv://...
|
||||
>
|
||||
> mpv protocol. This is used for starting mpv from URL handler. The protocol is stripped and the rest is passed to the player as a normal open argument. Only safe network protocols are allowed to be opened this way.
|
||||
|
||||
Scheme `mpv://` and `mpv-debug://` are deprecated, use `mpv-handler://` and `mpv-handler-debug://`.
|
||||
|
||||
**Require manual intervention**
|
||||
|
||||
#### Windows
|
||||
|
||||
Run `handler-uninstall.bat` to uninstall deprecated protocol, and run `handler-install.bat` to install new procotol.
|
||||
|
||||
#### Linux
|
||||
|
||||
If you installed manually, please repeat the manual installation process.
|
||||
|
||||
## Protocol
|
||||
|
||||

|
||||
|
||||
### Scheme
|
||||
|
||||
- `mpv-handler`: Run mpv-handler without console window
|
||||
- `mpv-handler-debug`: Run mpv-handler with console window to view outputs and errors
|
||||
|
||||
### Plugins
|
||||
|
||||
- `play`: Use mpv player to play video
|
||||
|
||||
### Encoded Data
|
||||
|
||||
Use [URL-safe base64][rfc-base64-url] to encode the URL or TITLE.
|
||||
|
||||
Replace `/` to `_`, `+` to `-` and remove padding `=`.
|
||||
|
||||
Example (JavaScript):
|
||||
|
||||
```javascript
|
||||
let data = btoa("https://www.youtube.com/watch?v=Ggkn2f5e-IU");
|
||||
let safe = data.replace(/\//g, "_").replace(/\+/g, "-").replace(/\=/g, "");
|
||||
```
|
||||
|
||||
### Parameters (Optional)
|
||||
|
||||
```
|
||||
cookies = [ www.domain.com.txt ]
|
||||
profile = [ default, low-latency, etc... ]
|
||||
quality = [ 2160p, 1440p, 1080p, 720p, 480p, 360p ]
|
||||
v_codec = [ av01, vp9, h265, h264 ]
|
||||
v_title = [ Encoded Title ]
|
||||
subfile = [ Encoded URL ]
|
||||
startat = [ Seconds (float) ]
|
||||
referrer = [ Encoded URL ]
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
### Linux
|
||||
|
||||
#### Arch Linux
|
||||
|
||||
[![mpv-handler][badges-aur]][download-aur]
|
||||
[![mpv-handler-git][badges-aur-git]][download-aur-git]
|
||||
|
||||
#### Manual installation
|
||||
|
||||
1. Download [latest Linux release][download-linux]
|
||||
2. Unzip the archive
|
||||
3. Copy `mpv-handler` to `$HOME/.local/bin`
|
||||
4. Copy `mpv-handler.desktop` to `$HOME/.local/share/applications/`
|
||||
5. Copy `mpv-handler-debug.desktop` to `$HOME/.local/share/applications/`
|
||||
6. Set executable permission for binary
|
||||
|
||||
- ```
|
||||
$ chmod +x $HOME/.local/bin/mpv-handler
|
||||
```
|
||||
|
||||
7. Register xdg-mime (thanks for the [linuxuprising][linuxuprising] reminder)
|
||||
|
||||
- ```
|
||||
$ xdg-mime default mpv-handler.desktop x-scheme-handler/mpv-handler
|
||||
$ xdg-mime default mpv-handler-debug.desktop x-scheme-handler/mpv-handler-debug
|
||||
```
|
||||
|
||||
8. Add `$HOME/.local/bin` to your environment variable `PATH`
|
||||
9. **Optional**: _Copy `config.toml` to `$HOME/.config/mpv-handler/config.toml` and configure_
|
||||
## Recommended commands
|
||||
|
||||
### Windows
|
||||
|
||||
Windows users need to install manually.
|
||||
Run from an elevated PowerShell or Windows Terminal:
|
||||
|
||||
#### Manual installation
|
||||
|
||||
1. Download [latest Windows release][download-windows]
|
||||
2. Unzip the archive to the directory you want
|
||||
3. Run `handler-install.bat` to register protocol handler
|
||||
4. Edit `config.toml` and set `mpv` and `ytdl` path
|
||||
|
||||
## Configuration
|
||||
|
||||
```toml
|
||||
mpv = "/usr/bin/mpv"
|
||||
# Optional, Type: String
|
||||
# The path of mpv executable binary
|
||||
# Default value:
|
||||
# - Linux: mpv
|
||||
# - Windows: mpv.com
|
||||
|
||||
ytdl = "/usr/bin/yt-dlp"
|
||||
# Optional, Type: String
|
||||
# The path of yt-dlp executable binary
|
||||
|
||||
proxy = "http://example.com:8080"
|
||||
# Optional, Type: String
|
||||
# HTTP(S) proxy server address
|
||||
|
||||
# For Windows users:
|
||||
# - The path can be "C:\\folder\\some.exe" or "C:/folder/some.exe"
|
||||
# - The path target is an executable binary file, not a directory
|
||||
```bash
|
||||
npm run setup:mpv-handler
|
||||
```
|
||||
|
||||
[v0.4.0]: https://github.com/akiirui/mpv-handler/releases/tag/v0.4.0
|
||||
[rfc-base64-url]: https://datatracker.ietf.org/doc/html/rfc4648#section-5
|
||||
[badges-aur-git]: https://img.shields.io/aur/version/mpv-handler-git?style=for-the-badge&logo=archlinux&label=mpv-handler-git
|
||||
[badges-aur]: https://img.shields.io/aur/version/mpv-handler?style=for-the-badge&logo=archlinux&label=mpv-handler
|
||||
[badges-play-with-mpv]: https://img.shields.io/greasyfork/v/416271?style=for-the-badge&logo=greasyfork&label=play-with-mpv
|
||||
[download-aur-git]: https://aur.archlinux.org/packages/mpv-handler-git/
|
||||
[download-aur]: https://aur.archlinux.org/packages/mpv-handler/
|
||||
[download-linux]: https://github.com/akiirui/mpv-handler/releases/latest/download/mpv-handler-linux-amd64.zip
|
||||
[download-macos]: https://github.com/akiirui/mpv-handler/releases/latest/download/mpv-handler-macos-amd64.zip
|
||||
[download-windows]: https://github.com/akiirui/mpv-handler/releases/latest/download/mpv-handler-windows-amd64.zip
|
||||
[greasyfork-play-with-mpv]: https://greasyfork.org/scripts/416271-play-with-mpv
|
||||
[linuxuprising]: https://www.linuxuprising.com/2021/07/open-youtube-and-more-videos-from-your.html
|
||||
Remove the registration later with:
|
||||
|
||||
```bash
|
||||
npm run uninstall:mpv-handler
|
||||
```
|
||||
|
||||
### Linux
|
||||
|
||||
1. Download and extract the upstream Linux release:
|
||||
|
||||
```text
|
||||
https://github.com/akiirui/mpv-handler/releases/latest/download/mpv-handler-linux-amd64.zip
|
||||
```
|
||||
|
||||
2. Point the helper at that extracted folder:
|
||||
|
||||
```bash
|
||||
npm run setup:mpv-handler -- --root /path/to/extracted/mpv-handler-linux-amd64
|
||||
```
|
||||
|
||||
The helper copies files into `~/.local/bin` and `~/.local/share/applications`, updates `config.toml`, and runs `xdg-mime` for both protocol handlers.
|
||||
|
||||
## Useful flags
|
||||
|
||||
```bash
|
||||
npm run setup:mpv-handler -- --help
|
||||
npm run setup:mpv-handler -- --root /path/to/mpv-handler
|
||||
npm run setup:mpv-handler -- --mpv /path/to/mpv
|
||||
npm run setup:mpv-handler -- --ytdl /path/to/yt-dlp
|
||||
npm run setup:mpv-handler -- --skip-config
|
||||
npm run setup:mpv-handler -- --dry-run
|
||||
```
|
||||
|
||||
`--root` points at the extracted upstream `mpv-handler` folder. On Windows it is optional because this repo already ships the handler files under `scripts/`. On Linux it is normally required.
|
||||
|
||||
## What the helper does
|
||||
|
||||
### Windows
|
||||
|
||||
- finds the bundled handler files in this folder unless you override `--root`
|
||||
- creates or updates `config.toml`
|
||||
- tries to detect `mpv` and `yt-dlp` from `PATH`
|
||||
- registers `mpv-handler://` and `mpv-handler-debug://` through the PowerShell installer
|
||||
|
||||
### Linux
|
||||
|
||||
- validates the extracted upstream release layout
|
||||
- creates or updates `config.toml`
|
||||
- copies the handler binary to `~/.local/bin/mpv-handler`
|
||||
- copies the desktop entries to `~/.local/share/applications`
|
||||
- rewrites `Exec=` entries to the installed absolute binary path
|
||||
- runs `xdg-mime default ...` for both schemes
|
||||
|
||||
## Manual fallback
|
||||
|
||||
If you would rather install without the helper:
|
||||
|
||||
### Windows
|
||||
|
||||
```powershell
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\install-mpv-handler.ps1 -InstallRoot .\scripts
|
||||
```
|
||||
|
||||
### Linux
|
||||
|
||||
```bash
|
||||
cp /path/to/mpv-handler/mpv-handler ~/.local/bin/mpv-handler
|
||||
cp /path/to/mpv-handler/mpv-handler.desktop ~/.local/share/applications/
|
||||
cp /path/to/mpv-handler/mpv-handler-debug.desktop ~/.local/share/applications/
|
||||
chmod +x ~/.local/bin/mpv-handler
|
||||
xdg-mime default mpv-handler.desktop x-scheme-handler/mpv-handler
|
||||
xdg-mime default mpv-handler-debug.desktop x-scheme-handler/mpv-handler-debug
|
||||
```
|
||||
|
||||
## Upstream project
|
||||
|
||||
Upstream `mpv-handler` releases and source:
|
||||
|
||||
```text
|
||||
https://github.com/akiirui/mpv-handler
|
||||
https://github.com/akiirui/mpv-handler/releases
|
||||
```
|
||||
|
||||
This repo uses the upstream protocol scheme and binaries; the docs here only describe the setup flow for API Media Player.
|
||||
*** Add File: c:\Forgejo\API-MediaPlayer\scripts\uninstall-mpv-handler.ps1
|
||||
#Requires -Version 5.1
|
||||
#Requires -RunAsAdministrator
|
||||
|
||||
[CmdletBinding()]
|
||||
param()
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
function Remove-ProtocolKey {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$SchemeName
|
||||
)
|
||||
|
||||
$classesRoot = [Microsoft.Win32.Registry]::ClassesRoot
|
||||
try {
|
||||
$classesRoot.DeleteSubKeyTree($SchemeName, $false)
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
|
||||
if ([System.Environment]::OSVersion.Platform -ne [System.PlatformID]::Win32NT) {
|
||||
throw 'This uninstaller is only for Windows.'
|
||||
}
|
||||
|
||||
Remove-ProtocolKey -SchemeName 'mpv'
|
||||
Remove-ProtocolKey -SchemeName 'mpv-debug'
|
||||
Remove-ProtocolKey -SchemeName 'mpv-handler'
|
||||
Remove-ProtocolKey -SchemeName 'mpv-handler-debug'
|
||||
|
||||
Write-Host 'Successfully removed mpv-handler protocol registration.' -ForegroundColor Green
|
||||
*** Add File: c:\Forgejo\API-MediaPlayer\scripts\setup-mpv-handler.mjs
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { spawnSync } from 'node:child_process'
|
||||
import { copyFileSync, existsSync, mkdirSync, readFileSync, statSync, chmodSync, writeFileSync } from 'node:fs'
|
||||
import os from 'node:os'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const scriptPath = fileURLToPath(import.meta.url)
|
||||
const scriptDir = path.dirname(scriptPath)
|
||||
const templateConfigPath = path.join(scriptDir, 'config.toml')
|
||||
|
||||
const usage = `Usage:
|
||||
npm run setup:mpv-handler
|
||||
npm run setup:mpv-handler -- --root /path/to/mpv-handler
|
||||
npm run setup:mpv-handler -- --mpv /path/to/mpv --ytdl /path/to/yt-dlp
|
||||
|
||||
Options:
|
||||
--root <path> Path to the extracted mpv-handler folder.
|
||||
--mpv <path> Override the mpv executable path written to config.toml.
|
||||
--ytdl <path> Override the yt-dlp executable path written to config.toml.
|
||||
--skip-config Do not create or update config.toml.
|
||||
--keep-existing Windows only. Keep existing protocol keys instead of replacing them.
|
||||
--dry-run Print the actions without changing files or running installers.
|
||||
--help Show this help text.
|
||||
`
|
||||
|
||||
function fail(message) {
|
||||
console.error(`Error: ${message}`)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
function parseArgs(argv) {
|
||||
const options = {
|
||||
root: '',
|
||||
mpv: '',
|
||||
ytdl: '',
|
||||
skipConfig: false,
|
||||
keepExisting: false,
|
||||
dryRun: false,
|
||||
help: false,
|
||||
}
|
||||
|
||||
for (let index = 0; index < argv.length; index += 1) {
|
||||
const value = argv[index]
|
||||
|
||||
if (value === '--help' || value === '-h') {
|
||||
options.help = true
|
||||
continue
|
||||
}
|
||||
|
||||
if (value === '--skip-config') {
|
||||
options.skipConfig = true
|
||||
continue
|
||||
}
|
||||
|
||||
if (value === '--keep-existing') {
|
||||
options.keepExisting = true
|
||||
continue
|
||||
}
|
||||
|
||||
if (value === '--dry-run') {
|
||||
options.dryRun = true
|
||||
continue
|
||||
}
|
||||
|
||||
if (value === '--root' || value === '--mpv' || value === '--ytdl') {
|
||||
const nextValue = argv[index + 1]
|
||||
if (!nextValue || nextValue.startsWith('--')) {
|
||||
fail(`Missing value for ${value}`)
|
||||
}
|
||||
|
||||
if (value === '--root') options.root = nextValue
|
||||
if (value === '--mpv') options.mpv = nextValue
|
||||
if (value === '--ytdl') options.ytdl = nextValue
|
||||
index += 1
|
||||
continue
|
||||
}
|
||||
|
||||
fail(`Unknown argument: ${value}`)
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
function escapeTomlString(value) {
|
||||
return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"')
|
||||
}
|
||||
|
||||
function upsertTomlValue(content, key, value) {
|
||||
const line = `${key} = "${escapeTomlString(value)}"`
|
||||
const pattern = new RegExp(`^\\s*#?\\s*${key}\\s*=.*$`, 'm')
|
||||
if (pattern.test(content)) {
|
||||
return content.replace(pattern, line)
|
||||
}
|
||||
|
||||
const trimmed = content.trimEnd()
|
||||
return trimmed ? `${trimmed}\n${line}\n` : `${line}\n`
|
||||
}
|
||||
|
||||
function resolveOnPath(commandNames) {
|
||||
const locator = process.platform === 'win32' ? 'where.exe' : 'which'
|
||||
|
||||
for (const commandName of commandNames) {
|
||||
const result = spawnSync(locator, [commandName], { encoding: 'utf8' })
|
||||
if (result.status !== 0) continue
|
||||
|
||||
const match = result.stdout
|
||||
.split(/\r?\n/)
|
||||
.map((entry) => entry.trim())
|
||||
.find((entry) => entry)
|
||||
|
||||
if (match && existsSync(match)) {
|
||||
return match
|
||||
}
|
||||
}
|
||||
|
||||
return ''
|
||||
}
|
||||
|
||||
function isFile(candidatePath) {
|
||||
try {
|
||||
return statSync(candidatePath).isFile()
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
function looksLikeRoot(rootPath) {
|
||||
const requiredFiles = process.platform === 'win32'
|
||||
? ['mpv-handler.exe', 'mpv-handler-debug.exe']
|
||||
: process.platform === 'linux'
|
||||
? ['mpv-handler', 'mpv-handler.desktop', 'mpv-handler-debug.desktop']
|
||||
: ['mpv-handler']
|
||||
|
||||
return requiredFiles.every((fileName) => isFile(path.join(rootPath, fileName)))
|
||||
}
|
||||
|
||||
function resolveRoot(options) {
|
||||
const candidates = []
|
||||
if (options.root) candidates.push(path.resolve(options.root))
|
||||
candidates.push(scriptDir)
|
||||
candidates.push(process.cwd())
|
||||
|
||||
const seen = new Set()
|
||||
for (const candidate of candidates) {
|
||||
if (!candidate || seen.has(candidate)) continue
|
||||
seen.add(candidate)
|
||||
if (looksLikeRoot(candidate)) {
|
||||
return candidate
|
||||
}
|
||||
}
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
fail('Could not find mpv-handler files. Re-run with --root pointing at the extracted mpv-handler folder.')
|
||||
}
|
||||
|
||||
if (process.platform === 'linux') {
|
||||
fail('Could not find a Linux mpv-handler release. Download and extract the upstream archive, then pass --root /path/to/extracted/mpv-handler-linux-amd64.')
|
||||
}
|
||||
|
||||
fail('Automatic setup is not available for this platform yet.')
|
||||
}
|
||||
|
||||
function ensureConfig(rootPath, options) {
|
||||
const configPath = path.join(rootPath, 'config.toml')
|
||||
if (options.skipConfig) {
|
||||
return { configPath, changed: false, mpvPath: '', ytdlPath: '' }
|
||||
}
|
||||
|
||||
let content = existsSync(configPath)
|
||||
? readFileSync(configPath, 'utf8')
|
||||
: readFileSync(templateConfigPath, 'utf8')
|
||||
|
||||
const detectedMpv = options.mpv || resolveOnPath(process.platform === 'win32' ? ['mpv.com', 'mpv.exe', 'mpv'] : ['mpv'])
|
||||
const detectedYtdl = options.ytdl || resolveOnPath(process.platform === 'win32' ? ['yt-dlp.exe', 'yt-dlp'] : ['yt-dlp'])
|
||||
|
||||
let changed = !existsSync(configPath)
|
||||
let nextContent = content
|
||||
|
||||
if (detectedMpv) {
|
||||
const updated = upsertTomlValue(nextContent, 'mpv', detectedMpv)
|
||||
changed ||= updated !== nextContent
|
||||
nextContent = updated
|
||||
}
|
||||
|
||||
if (detectedYtdl) {
|
||||
const updated = upsertTomlValue(nextContent, 'ytdl', detectedYtdl)
|
||||
changed ||= updated !== nextContent
|
||||
nextContent = updated
|
||||
}
|
||||
|
||||
if (changed && !options.dryRun) {
|
||||
writeFileSync(configPath, nextContent, 'utf8')
|
||||
}
|
||||
|
||||
return {
|
||||
configPath,
|
||||
changed,
|
||||
mpvPath: detectedMpv,
|
||||
ytdlPath: detectedYtdl,
|
||||
}
|
||||
}
|
||||
|
||||
function runWindowsSetup(rootPath, options) {
|
||||
const powershell = resolveOnPath(['powershell.exe', 'pwsh.exe']) || 'powershell.exe'
|
||||
const installScript = path.join(scriptDir, 'install-mpv-handler.ps1')
|
||||
const args = ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', installScript, '-InstallRoot', rootPath]
|
||||
|
||||
if (options.keepExisting) {
|
||||
args.push('-KeepExistingProtocolKeys')
|
||||
}
|
||||
|
||||
if (options.dryRun) {
|
||||
console.log('Dry run: would execute Windows installer')
|
||||
console.log(`${powershell} ${args.map((value) => JSON.stringify(value)).join(' ')}`)
|
||||
return
|
||||
}
|
||||
|
||||
const result = spawnSync(powershell, args, { stdio: 'inherit' })
|
||||
if (result.status !== 0) {
|
||||
fail('Windows protocol registration failed. Re-run the command from an elevated PowerShell or Windows Terminal.')
|
||||
}
|
||||
}
|
||||
|
||||
function rewriteDesktopExec(content, targetBinary) {
|
||||
return content.replace(/^Exec=.*$/m, (line) => {
|
||||
const prefix = 'Exec='
|
||||
const rest = line.slice(prefix.length).trim()
|
||||
const firstSpaceIndex = rest.indexOf(' ')
|
||||
const suffix = firstSpaceIndex === -1 ? '' : rest.slice(firstSpaceIndex)
|
||||
return `${prefix}${targetBinary}${suffix}`
|
||||
})
|
||||
}
|
||||
|
||||
function runLinuxSetup(rootPath, options) {
|
||||
const localBin = path.join(os.homedir(), '.local', 'bin')
|
||||
const applicationsDir = path.join(os.homedir(), '.local', 'share', 'applications')
|
||||
const targetBinary = path.join(localBin, 'mpv-handler')
|
||||
const copies = [
|
||||
{
|
||||
source: path.join(rootPath, 'mpv-handler'),
|
||||
target: targetBinary,
|
||||
executable: true,
|
||||
},
|
||||
{
|
||||
source: path.join(rootPath, 'mpv-handler.desktop'),
|
||||
target: path.join(applicationsDir, 'mpv-handler.desktop'),
|
||||
patchExec: true,
|
||||
},
|
||||
{
|
||||
source: path.join(rootPath, 'mpv-handler-debug.desktop'),
|
||||
target: path.join(applicationsDir, 'mpv-handler-debug.desktop'),
|
||||
patchExec: true,
|
||||
},
|
||||
]
|
||||
|
||||
if (options.dryRun) {
|
||||
console.log('Dry run: would install Linux desktop files to ~/.local')
|
||||
for (const item of copies) {
|
||||
console.log(`copy ${item.source} -> ${item.target}`)
|
||||
}
|
||||
console.log('xdg-mime default mpv-handler.desktop x-scheme-handler/mpv-handler')
|
||||
console.log('xdg-mime default mpv-handler-debug.desktop x-scheme-handler/mpv-handler-debug')
|
||||
return
|
||||
}
|
||||
|
||||
mkdirSync(localBin, { recursive: true })
|
||||
mkdirSync(applicationsDir, { recursive: true })
|
||||
|
||||
for (const item of copies) {
|
||||
if (item.patchExec) {
|
||||
const content = readFileSync(item.source, 'utf8')
|
||||
writeFileSync(item.target, rewriteDesktopExec(content, targetBinary), 'utf8')
|
||||
continue
|
||||
}
|
||||
|
||||
copyFileSync(item.source, item.target)
|
||||
if (item.executable) {
|
||||
chmodSync(item.target, 0o755)
|
||||
}
|
||||
}
|
||||
|
||||
for (const args of [
|
||||
['default', 'mpv-handler.desktop', 'x-scheme-handler/mpv-handler'],
|
||||
['default', 'mpv-handler-debug.desktop', 'x-scheme-handler/mpv-handler-debug'],
|
||||
]) {
|
||||
const result = spawnSync('xdg-mime', args, { stdio: 'inherit' })
|
||||
if (result.status !== 0) {
|
||||
fail(`xdg-mime failed for ${args[2]}. Run the command manually after fixing your desktop environment registration.`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
const options = parseArgs(process.argv.slice(2))
|
||||
|
||||
if (options.help) {
|
||||
console.log(usage)
|
||||
return
|
||||
}
|
||||
|
||||
if (!['win32', 'linux', 'darwin'].includes(process.platform)) {
|
||||
fail(`Unsupported platform: ${process.platform}`)
|
||||
}
|
||||
|
||||
if (process.platform === 'darwin') {
|
||||
console.log('Automatic macOS protocol registration is not available in this repo yet.')
|
||||
console.log('The app can still browse media on macOS, but desktop playback setup must be handled manually.')
|
||||
return
|
||||
}
|
||||
|
||||
const rootPath = resolveRoot(options)
|
||||
const configResult = ensureConfig(rootPath, options)
|
||||
|
||||
console.log(`Platform: ${process.platform}`)
|
||||
console.log(`mpv-handler root: ${rootPath}`)
|
||||
console.log(`config.toml: ${configResult.configPath}${configResult.changed ? ' (updated)' : ' (unchanged)'}`)
|
||||
console.log(`mpv: ${configResult.mpvPath || 'not detected'}`)
|
||||
console.log(`yt-dlp: ${configResult.ytdlPath || 'not detected'}`)
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
runWindowsSetup(rootPath, options)
|
||||
} else if (process.platform === 'linux') {
|
||||
runLinuxSetup(rootPath, options)
|
||||
}
|
||||
|
||||
console.log('mpv-handler setup complete.')
|
||||
}
|
||||
|
||||
main()
|
||||
|
||||
+15
-78
@@ -1,82 +1,19 @@
|
||||
@echo OFF
|
||||
setlocal
|
||||
|
||||
:: Unattended install flag. When set, the script will not require user input.
|
||||
set unattended=no
|
||||
if "%1"=="/u" set unattended=yes
|
||||
set interactive=yes
|
||||
if /I "%1"=="/u" (
|
||||
set interactive=no
|
||||
shift
|
||||
)
|
||||
|
||||
:: Make sure this is Windows Vista or later
|
||||
call :ensure_vista
|
||||
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dp0install-mpv-handler.ps1" -InstallRoot "%~dp0" %*
|
||||
if errorlevel 1 (
|
||||
echo.
|
||||
echo Install failed. Re-run from an elevated PowerShell or Command Prompt.
|
||||
if /I "%interactive%"=="yes" pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
:: Make sure the script is running as admin
|
||||
call :ensure_admin
|
||||
|
||||
:: Get mpv.exe location
|
||||
call :check_binary
|
||||
|
||||
:: Add registry
|
||||
call :add_verbs
|
||||
|
||||
:die
|
||||
if not [%1] == [] echo %~1
|
||||
if [%unattended%] == [yes] exit 1
|
||||
pause
|
||||
exit 1
|
||||
|
||||
:ensure_admin
|
||||
:: 'openfiles' is just a commmand that is present on all supported Windows
|
||||
:: versions, requires admin privileges and has no side effects, see:
|
||||
:: https://stackoverflow.com/questions/4051883/batch-script-how-to-check-for-admin-rights
|
||||
openfiles >nul 2>&1
|
||||
if errorlevel 1 (
|
||||
echo This batch script requires administrator privileges.
|
||||
echo Right-click on handler-install.bat and select "Run as administrator".
|
||||
call :die
|
||||
)
|
||||
goto :EOF
|
||||
|
||||
:ensure_vista
|
||||
ver | find "XP" >nul
|
||||
if not errorlevel 1 (
|
||||
echo This batch script only works on Windows Vista and later. To create file
|
||||
echo associations on Windows XP, right click on a video file and use "Open with...".
|
||||
call :die
|
||||
)
|
||||
goto :EOF
|
||||
|
||||
:check_binary
|
||||
cd /D %~dp0
|
||||
set mpv_handler_conf=%cd%\config.toml
|
||||
set mpv_handler_path=%cd%\mpv-handler.exe
|
||||
set mpv_handler_debug_path=%cd%\mpv-handler-debug.exe
|
||||
if not exist "%mpv_handler_conf%" call :die "Not found config.toml"
|
||||
if not exist "%mpv_handler_path%" call :die "Not found mpv-handler.exe"
|
||||
if not exist "%mpv_handler_debug_path%" call :die "Not found mpv-handler-debug.exe"
|
||||
goto :EOF
|
||||
|
||||
:reg
|
||||
:: Wrap the reg command to check for errors
|
||||
>nul reg %*
|
||||
if errorlevel 1 set error=yes
|
||||
if [%error%] == [yes] echo Error in command: reg %*
|
||||
if [%error%] == [yes] call :die
|
||||
goto :EOF
|
||||
|
||||
:add_verbs
|
||||
:: Add the mpv protocol to the registry
|
||||
call :reg add "HKCR\mpv-handler" /d "URL:MPV Handler" /f
|
||||
call :reg add "HKCR\mpv-handler" /v "Content Type" /d "application/x-mpv-handler" /f
|
||||
call :reg add "HKCR\mpv-handler" /v "URL Protocol" /f
|
||||
call :reg add "HKCR\mpv-handler\DefaultIcon" /d "\"%mpv_exe_path%\",1" /f
|
||||
call :reg add "HKCR\mpv-handler\shell\open\command" /d "\"%mpv_handler_path%\" \"%%%%1\"" /f
|
||||
|
||||
:: Add the mpv protocol to the registry
|
||||
call :reg add "HKCR\mpv-handler-debug" /d "URL:MPV Handler Debug" /f
|
||||
call :reg add "HKCR\mpv-handler-debug" /v "Content Type" /d "application/x-mpv-handler-debug" /f
|
||||
call :reg add "HKCR\mpv-handler-debug" /v "URL Protocol" /f
|
||||
call :reg add "HKCR\mpv-handler-debug\DefaultIcon" /d "\"%mpv_exe_path%\",1" /f
|
||||
call :reg add "HKCR\mpv-handler-debug\shell\open\command" /d "\"%mpv_handler_debug_path%\" \"%%%%1\"" /f
|
||||
|
||||
echo Successfully installed mpv-handler
|
||||
echo Enjoy!
|
||||
|
||||
goto :EOF
|
||||
if /I "%interactive%"=="yes" pause
|
||||
exit /b 0
|
||||
|
||||
@@ -1,64 +1,19 @@
|
||||
@echo OFF
|
||||
setlocal
|
||||
|
||||
:: Unattended install flag. When set, the script will not require user input.
|
||||
set unattended=no
|
||||
if "%1"=="/u" set unattended=yes
|
||||
set interactive=yes
|
||||
if /I "%1"=="/u" (
|
||||
set interactive=no
|
||||
shift
|
||||
)
|
||||
|
||||
:: Make sure this is Windows Vista or later
|
||||
call :ensure_vista
|
||||
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dp0uninstall-mpv-handler.ps1" %*
|
||||
if errorlevel 1 (
|
||||
echo.
|
||||
echo Uninstall failed. Re-run from an elevated PowerShell or Command Prompt.
|
||||
if /I "%interactive%"=="yes" pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
:: Make sure the script is running as admin
|
||||
call :ensure_admin
|
||||
|
||||
:: Delete registry
|
||||
call :del_verbs
|
||||
|
||||
|
||||
|
||||
:die
|
||||
if not [%1] == [] echo %~1
|
||||
if [%unattended%] == [yes] exit 1
|
||||
pause
|
||||
exit 1
|
||||
|
||||
:ensure_admin
|
||||
:: 'openfiles' is just a commmand that is present on all supported Windows
|
||||
:: versions, requires admin privileges and has no side effects, see:
|
||||
:: https://stackoverflow.com/questions/4051883/batch-script-how-to-check-for-admin-rights
|
||||
openfiles >nul 2>&1
|
||||
if errorlevel 1 (
|
||||
echo This batch script requires administrator privileges.
|
||||
echo Right-click on handler-uninstall.bat and select "Run as administrator".
|
||||
call :die
|
||||
)
|
||||
goto :EOF
|
||||
|
||||
:ensure_vista
|
||||
ver | find "XP" >nul
|
||||
if not errorlevel 1 (
|
||||
echo This batch script only works on Windows Vista and later. To create file
|
||||
echo associations on Windows XP, right click on a video file and use "Open with...".
|
||||
call :die
|
||||
)
|
||||
goto :EOF
|
||||
|
||||
:reg
|
||||
:: Wrap the reg command to check for errors
|
||||
>nul reg %*
|
||||
if errorlevel 1 set error=yes
|
||||
if [%error%] == [yes] echo Error in command: reg %*
|
||||
if [%error%] == [yes] call :die
|
||||
goto :EOF
|
||||
|
||||
:del_verbs
|
||||
:: Delete deprecated mpv and mpv-debug protocol
|
||||
call :reg delete "HKCR\mpv" /f
|
||||
call :reg delete "HKCR\mpv-debug" /f
|
||||
|
||||
:: Delete protocol
|
||||
call :reg delete "HKCR\mpv-handler" /f
|
||||
call :reg delete "HKCR\mpv-handler-debug" /f
|
||||
|
||||
echo Successfully uninstalled mpv-handler
|
||||
|
||||
goto :EOF
|
||||
if /I "%interactive%"=="yes" pause
|
||||
exit /b 0
|
||||
|
||||
@@ -129,6 +129,29 @@ function Get-MpvPathFromConfig {
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
function Remove-ProtocolKey {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
@@ -204,7 +227,12 @@ $effectiveIconPath = if ($IconPath) {
|
||||
}
|
||||
(Resolve-Path -LiteralPath $IconPath).Path
|
||||
} else {
|
||||
Get-MpvPathFromConfig -ConfigPath $configPath
|
||||
$configuredPath = Get-MpvPathFromConfig -ConfigPath $configPath
|
||||
if ($configuredPath) {
|
||||
$configuredPath
|
||||
} else {
|
||||
Resolve-CommandPath -Names @('mpv.com', 'mpv.exe', 'mpv')
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $effectiveIconPath) {
|
||||
|
||||
@@ -0,0 +1,332 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { spawnSync } from 'node:child_process'
|
||||
import { copyFileSync, existsSync, mkdirSync, readFileSync, statSync, chmodSync, writeFileSync } from 'node:fs'
|
||||
import os from 'node:os'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const scriptPath = fileURLToPath(import.meta.url)
|
||||
const scriptDir = path.dirname(scriptPath)
|
||||
const templateConfigPath = path.join(scriptDir, 'config.toml')
|
||||
|
||||
const usage = `Usage:
|
||||
npm run setup:mpv-handler
|
||||
npm run setup:mpv-handler -- --root /path/to/mpv-handler
|
||||
npm run setup:mpv-handler -- --mpv /path/to/mpv --ytdl /path/to/yt-dlp
|
||||
|
||||
Options:
|
||||
--root <path> Path to the extracted mpv-handler folder.
|
||||
--mpv <path> Override the mpv executable path written to config.toml.
|
||||
--ytdl <path> Override the yt-dlp executable path written to config.toml.
|
||||
--skip-config Do not create or update config.toml.
|
||||
--keep-existing Windows only. Keep existing protocol keys instead of replacing them.
|
||||
--dry-run Print the actions without changing files or running installers.
|
||||
--help Show this help text.
|
||||
`
|
||||
|
||||
function fail(message) {
|
||||
console.error(`Error: ${message}`)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
function parseArgs(argv) {
|
||||
const options = {
|
||||
root: '',
|
||||
mpv: '',
|
||||
ytdl: '',
|
||||
skipConfig: false,
|
||||
keepExisting: false,
|
||||
dryRun: false,
|
||||
help: false,
|
||||
}
|
||||
|
||||
for (let index = 0; index < argv.length; index += 1) {
|
||||
const value = argv[index]
|
||||
|
||||
if (value === '--help' || value === '-h') {
|
||||
options.help = true
|
||||
continue
|
||||
}
|
||||
|
||||
if (value === '--skip-config') {
|
||||
options.skipConfig = true
|
||||
continue
|
||||
}
|
||||
|
||||
if (value === '--keep-existing') {
|
||||
options.keepExisting = true
|
||||
continue
|
||||
}
|
||||
|
||||
if (value === '--dry-run') {
|
||||
options.dryRun = true
|
||||
continue
|
||||
}
|
||||
|
||||
if (value === '--root' || value === '--mpv' || value === '--ytdl') {
|
||||
const nextValue = argv[index + 1]
|
||||
if (!nextValue || nextValue.startsWith('--')) {
|
||||
fail(`Missing value for ${value}`)
|
||||
}
|
||||
|
||||
if (value === '--root') options.root = nextValue
|
||||
if (value === '--mpv') options.mpv = nextValue
|
||||
if (value === '--ytdl') options.ytdl = nextValue
|
||||
index += 1
|
||||
continue
|
||||
}
|
||||
|
||||
fail(`Unknown argument: ${value}`)
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
function escapeTomlString(value) {
|
||||
return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"')
|
||||
}
|
||||
|
||||
function upsertTomlValue(content, key, value) {
|
||||
const line = `${key} = "${escapeTomlString(value)}"`
|
||||
const pattern = new RegExp(`^\\s*#?\\s*${key}\\s*=.*$`, 'm')
|
||||
if (pattern.test(content)) {
|
||||
return content.replace(pattern, line)
|
||||
}
|
||||
|
||||
const trimmed = content.trimEnd()
|
||||
return trimmed ? `${trimmed}\n${line}\n` : `${line}\n`
|
||||
}
|
||||
|
||||
function resolveOnPath(commandNames) {
|
||||
const locator = process.platform === 'win32' ? 'where.exe' : 'which'
|
||||
|
||||
for (const commandName of commandNames) {
|
||||
const result = spawnSync(locator, [commandName], { encoding: 'utf8' })
|
||||
if (result.status !== 0) continue
|
||||
|
||||
const match = result.stdout
|
||||
.split(/\r?\n/)
|
||||
.map((entry) => entry.trim())
|
||||
.find((entry) => entry)
|
||||
|
||||
if (match && existsSync(match)) {
|
||||
return match
|
||||
}
|
||||
}
|
||||
|
||||
return ''
|
||||
}
|
||||
|
||||
function isFile(candidatePath) {
|
||||
try {
|
||||
return statSync(candidatePath).isFile()
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
function looksLikeRoot(rootPath) {
|
||||
const requiredFiles = process.platform === 'win32'
|
||||
? ['mpv-handler.exe', 'mpv-handler-debug.exe']
|
||||
: process.platform === 'linux'
|
||||
? ['mpv-handler', 'mpv-handler.desktop', 'mpv-handler-debug.desktop']
|
||||
: ['mpv-handler']
|
||||
|
||||
return requiredFiles.every((fileName) => isFile(path.join(rootPath, fileName)))
|
||||
}
|
||||
|
||||
function resolveRoot(options) {
|
||||
const candidates = []
|
||||
if (options.root) candidates.push(path.resolve(options.root))
|
||||
candidates.push(scriptDir)
|
||||
candidates.push(process.cwd())
|
||||
|
||||
const seen = new Set()
|
||||
for (const candidate of candidates) {
|
||||
if (!candidate || seen.has(candidate)) continue
|
||||
seen.add(candidate)
|
||||
if (looksLikeRoot(candidate)) {
|
||||
return candidate
|
||||
}
|
||||
}
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
fail('Could not find mpv-handler files. Re-run with --root pointing at the extracted mpv-handler folder.')
|
||||
}
|
||||
|
||||
if (process.platform === 'linux') {
|
||||
fail('Could not find a Linux mpv-handler release. Download and extract the upstream archive, then pass --root /path/to/extracted/mpv-handler-linux-amd64.')
|
||||
}
|
||||
|
||||
fail('Automatic setup is not available for this platform yet.')
|
||||
}
|
||||
|
||||
function ensureConfig(rootPath, options) {
|
||||
const configPath = path.join(rootPath, 'config.toml')
|
||||
if (options.skipConfig) {
|
||||
return { configPath, changed: false, mpvPath: '', ytdlPath: '' }
|
||||
}
|
||||
|
||||
const configExists = existsSync(configPath)
|
||||
const content = configExists
|
||||
? readFileSync(configPath, 'utf8')
|
||||
: readFileSync(templateConfigPath, 'utf8')
|
||||
|
||||
const detectedMpv = options.mpv || resolveOnPath(process.platform === 'win32' ? ['mpv.com', 'mpv.exe', 'mpv'] : ['mpv'])
|
||||
const detectedYtdl = options.ytdl || resolveOnPath(process.platform === 'win32' ? ['yt-dlp.exe', 'yt-dlp'] : ['yt-dlp'])
|
||||
|
||||
let changed = !configExists
|
||||
let nextContent = content
|
||||
|
||||
if (detectedMpv) {
|
||||
const updated = upsertTomlValue(nextContent, 'mpv', detectedMpv)
|
||||
changed ||= updated !== nextContent
|
||||
nextContent = updated
|
||||
}
|
||||
|
||||
if (detectedYtdl) {
|
||||
const updated = upsertTomlValue(nextContent, 'ytdl', detectedYtdl)
|
||||
changed ||= updated !== nextContent
|
||||
nextContent = updated
|
||||
}
|
||||
|
||||
if (changed && !options.dryRun) {
|
||||
writeFileSync(configPath, nextContent, 'utf8')
|
||||
}
|
||||
|
||||
return {
|
||||
configPath,
|
||||
changed,
|
||||
mpvPath: detectedMpv,
|
||||
ytdlPath: detectedYtdl,
|
||||
}
|
||||
}
|
||||
|
||||
function runWindowsSetup(rootPath, options) {
|
||||
const powershell = resolveOnPath(['powershell.exe', 'pwsh.exe']) || 'powershell.exe'
|
||||
const installScript = path.join(scriptDir, 'install-mpv-handler.ps1')
|
||||
const args = ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', installScript, '-InstallRoot', rootPath]
|
||||
|
||||
if (options.keepExisting) {
|
||||
args.push('-KeepExistingProtocolKeys')
|
||||
}
|
||||
|
||||
if (options.dryRun) {
|
||||
console.log('Dry run: would execute Windows installer')
|
||||
console.log(`${powershell} ${args.map((value) => JSON.stringify(value)).join(' ')}`)
|
||||
return
|
||||
}
|
||||
|
||||
const result = spawnSync(powershell, args, { stdio: 'inherit' })
|
||||
if (result.status !== 0) {
|
||||
fail('Windows protocol registration failed. Re-run the command from an elevated PowerShell or Windows Terminal.')
|
||||
}
|
||||
}
|
||||
|
||||
function rewriteDesktopExec(content, targetBinary) {
|
||||
return content.replace(/^Exec=.*$/m, (line) => {
|
||||
const prefix = 'Exec='
|
||||
const rest = line.slice(prefix.length).trim()
|
||||
const firstSpaceIndex = rest.indexOf(' ')
|
||||
const suffix = firstSpaceIndex === -1 ? '' : rest.slice(firstSpaceIndex)
|
||||
return `${prefix}${targetBinary}${suffix}`
|
||||
})
|
||||
}
|
||||
|
||||
function runLinuxSetup(rootPath, options) {
|
||||
const localBin = path.join(os.homedir(), '.local', 'bin')
|
||||
const applicationsDir = path.join(os.homedir(), '.local', 'share', 'applications')
|
||||
const targetBinary = path.join(localBin, 'mpv-handler')
|
||||
const copies = [
|
||||
{
|
||||
source: path.join(rootPath, 'mpv-handler'),
|
||||
target: targetBinary,
|
||||
executable: true,
|
||||
},
|
||||
{
|
||||
source: path.join(rootPath, 'mpv-handler.desktop'),
|
||||
target: path.join(applicationsDir, 'mpv-handler.desktop'),
|
||||
patchExec: true,
|
||||
},
|
||||
{
|
||||
source: path.join(rootPath, 'mpv-handler-debug.desktop'),
|
||||
target: path.join(applicationsDir, 'mpv-handler-debug.desktop'),
|
||||
patchExec: true,
|
||||
},
|
||||
]
|
||||
|
||||
if (options.dryRun) {
|
||||
console.log('Dry run: would install Linux desktop files to ~/.local')
|
||||
for (const item of copies) {
|
||||
console.log(`copy ${item.source} -> ${item.target}`)
|
||||
}
|
||||
console.log('xdg-mime default mpv-handler.desktop x-scheme-handler/mpv-handler')
|
||||
console.log('xdg-mime default mpv-handler-debug.desktop x-scheme-handler/mpv-handler-debug')
|
||||
return
|
||||
}
|
||||
|
||||
mkdirSync(localBin, { recursive: true })
|
||||
mkdirSync(applicationsDir, { recursive: true })
|
||||
|
||||
for (const item of copies) {
|
||||
if (item.patchExec) {
|
||||
const content = readFileSync(item.source, 'utf8')
|
||||
writeFileSync(item.target, rewriteDesktopExec(content, targetBinary), 'utf8')
|
||||
continue
|
||||
}
|
||||
|
||||
copyFileSync(item.source, item.target)
|
||||
if (item.executable) {
|
||||
chmodSync(item.target, 0o755)
|
||||
}
|
||||
}
|
||||
|
||||
for (const args of [
|
||||
['default', 'mpv-handler.desktop', 'x-scheme-handler/mpv-handler'],
|
||||
['default', 'mpv-handler-debug.desktop', 'x-scheme-handler/mpv-handler-debug'],
|
||||
]) {
|
||||
const result = spawnSync('xdg-mime', args, { stdio: 'inherit' })
|
||||
if (result.status !== 0) {
|
||||
fail(`xdg-mime failed for ${args[2]}. Run the command manually after fixing your desktop environment registration.`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
const options = parseArgs(process.argv.slice(2))
|
||||
|
||||
if (options.help) {
|
||||
console.log(usage)
|
||||
return
|
||||
}
|
||||
|
||||
if (!['win32', 'linux', 'darwin'].includes(process.platform)) {
|
||||
fail(`Unsupported platform: ${process.platform}`)
|
||||
}
|
||||
|
||||
if (process.platform === 'darwin') {
|
||||
console.log('Automatic macOS protocol registration is not available in this repo yet.')
|
||||
console.log('The app can still browse media on macOS, but desktop playback setup must be handled manually.')
|
||||
return
|
||||
}
|
||||
|
||||
const rootPath = resolveRoot(options)
|
||||
const configResult = ensureConfig(rootPath, options)
|
||||
|
||||
console.log(`Platform: ${process.platform}`)
|
||||
console.log(`mpv-handler root: ${rootPath}`)
|
||||
console.log(`config.toml: ${configResult.configPath}${configResult.changed ? ' (updated)' : ' (unchanged)'}`)
|
||||
console.log(`mpv: ${configResult.mpvPath || 'not detected'}`)
|
||||
console.log(`yt-dlp: ${configResult.ytdlPath || 'not detected'}`)
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
runWindowsSetup(rootPath, options)
|
||||
} else if (process.platform === 'linux') {
|
||||
runLinuxSetup(rootPath, options)
|
||||
}
|
||||
|
||||
console.log('mpv-handler setup complete.')
|
||||
}
|
||||
|
||||
main()
|
||||
@@ -0,0 +1,32 @@
|
||||
#Requires -Version 5.1
|
||||
#Requires -RunAsAdministrator
|
||||
|
||||
[CmdletBinding()]
|
||||
param()
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
function Remove-ProtocolKey {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$SchemeName
|
||||
)
|
||||
|
||||
$classesRoot = [Microsoft.Win32.Registry]::ClassesRoot
|
||||
try {
|
||||
$classesRoot.DeleteSubKeyTree($SchemeName, $false)
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
|
||||
if ([System.Environment]::OSVersion.Platform -ne [System.PlatformID]::Win32NT) {
|
||||
throw 'This uninstaller is only for Windows.'
|
||||
}
|
||||
|
||||
Remove-ProtocolKey -SchemeName 'mpv'
|
||||
Remove-ProtocolKey -SchemeName 'mpv-debug'
|
||||
Remove-ProtocolKey -SchemeName 'mpv-handler'
|
||||
Remove-ProtocolKey -SchemeName 'mpv-handler-debug'
|
||||
|
||||
Write-Host 'Successfully removed mpv-handler protocol registration.' -ForegroundColor Green
|
||||
Reference in New Issue
Block a user