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
|
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:
|
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
|
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
|
### 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
|
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:
|
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.
|
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
|
## Useful flags
|
||||||
|
|
||||||
@@ -74,6 +74,7 @@ npm run setup:mpv-handler -- --dry-run
|
|||||||
|
|
||||||
- validates the extracted upstream release layout
|
- 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
|
- 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`
|
- creates or updates `config.toml`
|
||||||
- copies the handler binary to `~/.local/bin/mpv-handler`
|
- copies the handler binary to `~/.local/bin/mpv-handler`
|
||||||
- copies the desktop entries to `~/.local/share/applications`
|
- 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 scriptPath = fileURLToPath(import.meta.url)
|
||||||
const scriptDir = path.dirname(scriptPath)
|
const scriptDir = path.dirname(scriptPath)
|
||||||
const templateConfigPath = path.join(scriptDir, 'config.toml')
|
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_REPO = 'https://github.com/akiirui/mpv-handler.git'
|
||||||
const UPSTREAM_MPV_HANDLER_REF = 'v0.4.2'
|
const UPSTREAM_MPV_HANDLER_REF = 'v0.4.2'
|
||||||
|
|
||||||
@@ -216,6 +219,27 @@ function prepareLinuxSourceBuildRoot(options) {
|
|||||||
return stageDir
|
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) {
|
function resolveRoot(options) {
|
||||||
const resolvedRoot = findRoot(options)
|
const resolvedRoot = findRoot(options)
|
||||||
if (resolvedRoot) return resolvedRoot
|
if (resolvedRoot) return resolvedRoot
|
||||||
@@ -225,13 +249,21 @@ function resolveRoot(options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (process.platform === 'linux') {
|
if (process.platform === 'linux') {
|
||||||
if (process.arch !== 'x64' && !options.skipSourceBuild) {
|
if (process.arch !== 'x64') {
|
||||||
return prepareLinuxSourceBuildRoot(options)
|
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'
|
const archHint = process.arch === 'x64'
|
||||||
? 'Download and extract the upstream archive, then pass --root /path/to/extracted/mpv-handler-linux-amd64.'
|
? '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}`)
|
fail(`Could not find a Linux mpv-handler release. ${archHint}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user