update README.md and add linux-mpv-handler scripts
This commit is contained in:
@@ -84,7 +84,7 @@ Run this on the Linux desktop client that should receive `mpv-handler://` links,
|
||||
https://github.com/akiirui/mpv-handler/releases/latest/download/mpv-handler-linux-amd64.zip
|
||||
```
|
||||
|
||||
The upstream project currently publishes an official Linux release for `amd64` only. On Raspberry Pi or other ARM Linux systems, `npm run setup:mpv-handler` now tries to build a compatible binary automatically from upstream source if both `git` and Rust `cargo` are installed. If you prefer not to build locally, pass `--skip-source-build` and provide `--root` with a compatible extracted folder instead.
|
||||
The upstream project currently publishes an official Linux release for `amd64` only. On Raspberry Pi or other ARM Linux systems, `npm run setup:mpv-handler` now tries to build a compatible binary automatically from upstream source if both `git` and Rust `cargo` are installed. If they are not available, it falls back to a bundled Python-based Linux protocol handler that supports this app's `mpv-handler://play/...` URLs without Rust.
|
||||
|
||||
3. Run the helper against the extracted folder:
|
||||
|
||||
@@ -92,7 +92,7 @@ The upstream project currently publishes an official Linux release for `amd64` o
|
||||
npm run setup:mpv-handler -- --root /path/to/extracted/mpv-handler-linux-amd64
|
||||
```
|
||||
|
||||
On Linux the helper copies the binary and desktop files into `~/.local`, writes `config.toml` to `~/.config/mpv-handler/config.toml` (or `$XDG_CONFIG_HOME/mpv-handler/config.toml`), and runs `xdg-mime` for both protocol handlers. On non-`x64` Linux it also auto-builds a staged `mpv-handler` root under `~/.cache/api-mediaplayer/` before installing, unless you pass `--skip-source-build`.
|
||||
On Linux the helper copies the binary and desktop files into `~/.local`, writes `config.toml` to `~/.config/mpv-handler/config.toml` (or `$XDG_CONFIG_HOME/mpv-handler/config.toml`), and runs `xdg-mime` for both protocol handlers. On non-`x64` Linux it first prefers an automatic upstream source build under `~/.cache/api-mediaplayer/` when `git` and `cargo` are available, and otherwise falls back to the bundled Python handler.
|
||||
|
||||
### Android
|
||||
|
||||
|
||||
+3
-2
@@ -35,7 +35,7 @@ npm run uninstall:mpv-handler
|
||||
https://github.com/akiirui/mpv-handler/releases/latest/download/mpv-handler-linux-amd64.zip
|
||||
```
|
||||
|
||||
The official upstream Linux release is currently `amd64` only. On Raspberry Pi or other ARM Linux systems, `npm run setup:mpv-handler` now tries to build a compatible `mpv-handler` binary automatically from upstream source if both `git` and Rust `cargo` are installed. If you do not want that behavior, pass `--skip-source-build` and provide `--root` yourself.
|
||||
The official upstream Linux release is currently `amd64` only. On Raspberry Pi or other ARM Linux systems, `npm run setup:mpv-handler` now tries to build a compatible `mpv-handler` binary automatically from upstream source if both `git` and Rust `cargo` are installed. If they are not available, the helper falls back to a bundled Python-based handler that supports this app's `mpv-handler://play/...` URLs without Rust.
|
||||
|
||||
2. Point the helper at that extracted folder:
|
||||
|
||||
@@ -45,7 +45,7 @@ npm run setup:mpv-handler -- --root /path/to/extracted/mpv-handler-linux-amd64
|
||||
|
||||
Run this on the Linux desktop client that should handle `mpv-handler://`, not on the machine that is only serving the web app.
|
||||
|
||||
The helper copies files into `~/.local/bin` and `~/.local/share/applications`, writes config to `~/.config/mpv-handler/config.toml` (or `$XDG_CONFIG_HOME/mpv-handler/config.toml`), and runs `xdg-mime` for both protocol handlers. On non-`x64` Linux it will first build and stage upstream source into `~/.cache/api-mediaplayer/` unless you pass `--skip-source-build`.
|
||||
The helper copies files into `~/.local/bin` and `~/.local/share/applications`, writes config to `~/.config/mpv-handler/config.toml` (or `$XDG_CONFIG_HOME/mpv-handler/config.toml`), and runs `xdg-mime` for both protocol handlers. On non-`x64` Linux it first tries to build and stage upstream source into `~/.cache/api-mediaplayer/`, and if `git` or `cargo` are unavailable it stages the bundled Python handler there instead.
|
||||
|
||||
## Useful flags
|
||||
|
||||
@@ -74,6 +74,7 @@ npm run setup:mpv-handler -- --dry-run
|
||||
|
||||
- validates the extracted upstream release layout
|
||||
- auto-builds upstream source on non-`x64` Linux when no compatible local root is available and `git` plus `cargo` are installed
|
||||
- falls back to a bundled Python `mpv-handler` implementation on non-`x64` Linux when source-build tooling is unavailable
|
||||
- creates or updates `config.toml`
|
||||
- copies the handler binary to `~/.local/bin/mpv-handler`
|
||||
- copies the desktop entries to `~/.local/share/applications`
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
[Desktop Entry]
|
||||
Name=mpv-handler-debug
|
||||
Exec=__MPV_HANDLER_EXEC__ %u
|
||||
Type=Application
|
||||
Terminal=true
|
||||
MimeType=x-scheme-handler/mpv-handler-debug;
|
||||
NoDisplay=true
|
||||
@@ -0,0 +1,7 @@
|
||||
[Desktop Entry]
|
||||
Name=mpv-handler
|
||||
Exec=__MPV_HANDLER_EXEC__ %u
|
||||
Type=Application
|
||||
Terminal=false
|
||||
MimeType=x-scheme-handler/mpv-handler;
|
||||
NoDisplay=true
|
||||
@@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import base64
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from urllib.parse import parse_qs, urlparse
|
||||
|
||||
|
||||
def decode_urlsafe_base64(value: str) -> str:
|
||||
padding = '=' * (-len(value) % 4)
|
||||
return base64.urlsafe_b64decode(f'{value}{padding}').decode('utf-8')
|
||||
|
||||
|
||||
def read_config_value(config_path: Path, key: str) -> str:
|
||||
if not config_path.is_file():
|
||||
return ''
|
||||
|
||||
pattern = re.compile(rf'^\s*#?\s*{re.escape(key)}\s*=\s*"([^"]*)"\s*$')
|
||||
for line in config_path.read_text(encoding='utf-8').splitlines():
|
||||
match = pattern.match(line)
|
||||
if match:
|
||||
return match.group(1).strip()
|
||||
return ''
|
||||
|
||||
|
||||
def resolve_mpv_command(config_path: Path) -> list[str]:
|
||||
configured_mpv = read_config_value(config_path, 'mpv')
|
||||
if configured_mpv:
|
||||
return [configured_mpv]
|
||||
return ['mpv']
|
||||
|
||||
|
||||
def build_mpv_command(target_url: str, title: str, config_path: Path) -> list[str]:
|
||||
command = resolve_mpv_command(config_path)
|
||||
if title:
|
||||
command.append(f'--force-media-title={title}')
|
||||
command.append(target_url)
|
||||
return command
|
||||
|
||||
|
||||
def parse_protocol_url(raw_url: str) -> tuple[str, str]:
|
||||
parsed = urlparse(raw_url)
|
||||
if parsed.scheme not in {'mpv-handler', 'mpv-handler-debug'}:
|
||||
raise ValueError(f'Unsupported scheme: {parsed.scheme}')
|
||||
|
||||
path_segments = [segment for segment in parsed.path.split('/') if segment]
|
||||
if not path_segments or path_segments[0] != 'play':
|
||||
raise ValueError('Unsupported mpv-handler plugin')
|
||||
if len(path_segments) < 2:
|
||||
raise ValueError('Missing encoded media URL')
|
||||
|
||||
target_url = decode_urlsafe_base64(path_segments[1])
|
||||
query = parse_qs(parsed.query)
|
||||
title = ''
|
||||
if query.get('v_title'):
|
||||
title = decode_urlsafe_base64(query['v_title'][0])
|
||||
return target_url, title
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if len(sys.argv) < 2:
|
||||
print('Expected protocol URL argument', file=sys.stderr)
|
||||
return 1
|
||||
|
||||
try:
|
||||
target_url, title = parse_protocol_url(sys.argv[1])
|
||||
except Exception as error:
|
||||
print(f'Failed to parse mpv-handler URL: {error}', file=sys.stderr)
|
||||
return 1
|
||||
|
||||
config_home = os.environ.get('XDG_CONFIG_HOME', '').strip()
|
||||
config_dir = Path(config_home) / 'mpv-handler' if config_home else Path.home() / '.config' / 'mpv-handler'
|
||||
config_path = config_dir / 'config.toml'
|
||||
command = build_mpv_command(target_url, title, config_path)
|
||||
|
||||
try:
|
||||
subprocess.Popen(command)
|
||||
except Exception as error:
|
||||
print(f'Failed to launch mpv: {error}', file=sys.stderr)
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
raise SystemExit(main())
|
||||
@@ -9,6 +9,9 @@ import { fileURLToPath } from 'node:url'
|
||||
const scriptPath = fileURLToPath(import.meta.url)
|
||||
const scriptDir = path.dirname(scriptPath)
|
||||
const templateConfigPath = path.join(scriptDir, 'config.toml')
|
||||
const bundledLinuxHandlerPath = path.join(scriptDir, 'linux-mpv-handler.py')
|
||||
const bundledLinuxDesktopPath = path.join(scriptDir, 'linux-mpv-handler.desktop')
|
||||
const bundledLinuxDebugDesktopPath = path.join(scriptDir, 'linux-mpv-handler-debug.desktop')
|
||||
const UPSTREAM_MPV_HANDLER_REPO = 'https://github.com/akiirui/mpv-handler.git'
|
||||
const UPSTREAM_MPV_HANDLER_REF = 'v0.4.2'
|
||||
|
||||
@@ -216,6 +219,27 @@ function prepareLinuxSourceBuildRoot(options) {
|
||||
return stageDir
|
||||
}
|
||||
|
||||
function prepareBundledLinuxHandlerRoot(options) {
|
||||
const cacheDir = getLinuxCacheDir()
|
||||
const stageDir = path.join(cacheDir, 'linux-bundled-handler')
|
||||
|
||||
if (options.dryRun) {
|
||||
console.log(`Dry run: would stage bundled Linux handler into ${stageDir}`)
|
||||
return stageDir
|
||||
}
|
||||
|
||||
mkdirSync(cacheDir, { recursive: true })
|
||||
mkdirSync(stageDir, { recursive: true })
|
||||
|
||||
copyFileSync(bundledLinuxHandlerPath, path.join(stageDir, 'mpv-handler'))
|
||||
copyFileSync(bundledLinuxDesktopPath, path.join(stageDir, 'mpv-handler.desktop'))
|
||||
copyFileSync(bundledLinuxDebugDesktopPath, path.join(stageDir, 'mpv-handler-debug.desktop'))
|
||||
copyFileSync(templateConfigPath, path.join(stageDir, 'config.toml'))
|
||||
chmodSync(path.join(stageDir, 'mpv-handler'), 0o755)
|
||||
|
||||
return stageDir
|
||||
}
|
||||
|
||||
function resolveRoot(options) {
|
||||
const resolvedRoot = findRoot(options)
|
||||
if (resolvedRoot) return resolvedRoot
|
||||
@@ -225,13 +249,21 @@ function resolveRoot(options) {
|
||||
}
|
||||
|
||||
if (process.platform === 'linux') {
|
||||
if (process.arch !== 'x64' && !options.skipSourceBuild) {
|
||||
return prepareLinuxSourceBuildRoot(options)
|
||||
if (process.arch !== 'x64') {
|
||||
if (!options.skipSourceBuild) {
|
||||
const gitPath = resolveOnPath(['git'])
|
||||
const cargoPath = resolveOnPath(['cargo'])
|
||||
if (gitPath && cargoPath) {
|
||||
return prepareLinuxSourceBuildRoot(options)
|
||||
}
|
||||
}
|
||||
|
||||
return prepareBundledLinuxHandlerRoot(options)
|
||||
}
|
||||
|
||||
const archHint = process.arch === 'x64'
|
||||
? 'Download and extract the upstream archive, then pass --root /path/to/extracted/mpv-handler-linux-amd64.'
|
||||
: `The upstream project only publishes an official linux-amd64 archive. Install git and cargo to allow automatic source builds, or build/obtain a compatible mpv-handler binary and pass --root /path/to/extracted/mpv-handler.`
|
||||
: `The upstream project only publishes an official linux-amd64 archive. Install git and cargo to allow automatic source builds, use the bundled fallback handler, or build/obtain a compatible mpv-handler binary and pass --root /path/to/extracted/mpv-handler.`
|
||||
fail(`Could not find a Linux mpv-handler release. ${archHint}`)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user