diff --git a/.editorconfig b/.editorconfig index 3b0653a..a8ced1c 100644 --- a/.editorconfig +++ b/.editorconfig @@ -6,4 +6,10 @@ indent_size = 4 end_of_line = lf charset = utf-8 trim_trailing_whitespace = false -insert_final_newline = false \ No newline at end of file +insert_final_newline = false + +[{Makefile}] +indent_style = tab + +[{*.html,*.js,*.json,*.css}] +indent_size = 2 \ No newline at end of file diff --git a/Makefile b/Makefile index 7ccbe43..56694d4 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,6 @@ SRC:=config.go ipc.go options.go $(wildcard cmd/open-in-mpv/*) EXT_SRC:=$(wildcard extension/Chrome/*) extension/Firefox/manifest.json +SCRIPTS_DIR:=scripts all: build/linux.tar build/mac.tar build/windows.tar build/firefox.zip @@ -9,8 +10,8 @@ builddir: build/linux/open-in-mpv: $(SRC) builddir @echo -e "\n# Building for Linux" env CGO_ENABLED=0 GOOS=linux GOARCh=amd64 go build -ldflags="-s -w" -o $@ ./cmd/open-in-mpv - cp scripts/install-protocol.sh $(dir $@) - cp scripts/open-in-mpv.desktop $(dir $@) + cp $(SCRIPTS_DIR)/install-protocol.sh $(dir $@) + cp $(SCRIPTS_DIR)/open-in-mpv.desktop $(dir $@) build/linux.tar: build/linux/open-in-mpv tar cf $@ -C $(dir $@)linux $(notdir $(wildcard build/linux/*)) @@ -22,7 +23,7 @@ build/mac/open-in-mpv.app: $(SRC) scripts/Info.plist builddir @mkdir -p $@/Contents env CGO_ENABLED=0 GOOS=darwin GOARCh=amd64 go build -ldflags="-s -w" -o $@/Contents/MacOS/open-in-mpv ./cmd/open-in-mpv cp config.yml $@/Contents/MacOS/ - cp scripts/Info.plist $@/Contents + cp $(SCRIPTS_DIR)/Info.plist $@/Contents build/mac.tar: build/mac/open-in-mpv.app tar cf $@ -C $(dir $@)/mac open-in-mpv.app @@ -30,7 +31,7 @@ build/mac.tar: build/mac/open-in-mpv.app build/windows/open-in-mpv.exe: $(SRC) builddir @echo -e "\n# Building for Windows" env CGO_ENABLED=0 GOOS=windows GOARCh=amd64 go build -ldflags="-s -w -H windowsgui" -o $@ ./cmd/open-in-mpv - cp scripts/install-protocol.reg $(dir $@) + cp $(SCRIPTS_DIR)/install-protocol.reg $(dir $@) build/windows.tar: build/windows/open-in-mpv.exe tar cf $@ -C $(dir $@)windows $(notdir $(wildcard build/windows/*)) @@ -45,7 +46,7 @@ install: build/linux/open-in-mpv cp build/linux/open-in-mpv /usr/bin install-protocol: - scripts/install-protocol.sh + $(SCRIPTS_DIR)/install-protocol.sh uninstall: rm /usr/bin/open-in-mpv diff --git a/README.md b/README.md index 9d9d5a1..f041e23 100644 --- a/README.md +++ b/README.md @@ -9,15 +9,14 @@ This is a simple web extension (for Chrome and Firefox) which helps open any video in the currently open tab in the [mpv player](https://mpv.io). -The extension itself shares a lot of code with the one from the awesome [iina](https://github.com/iina/iina), while the (bare) backend is written in Go (this is a rewrite from C++). +The extension itself shares a lot of code with the one from the awesome [iina](https://github.com/iina/iina), while the (bare) native binary is written in Go (this is a rewrite from C++). - [Installation](#installation) - [Configuration](#configuration) - - [Flag overrides](#flag-overrides) - - [Example](#example) - [The `mpv://` protocol](#the-mpv-protocol) - [Playlist and `enqueue` functionality](#playlist-and-enqueue-functionality) - [Player support](#player-support) +- [Supported protocols](#supported-protocols) ### Installation > Compiled binaries and packed extensions can be found in the [releases page](https://github.com/Baldomo/open-in-mpv/releases). @@ -38,31 +37,33 @@ The configuration file has to be named `config.yml` and can be placed in the sam The configuration file has the following structure: ```yaml -fake: [ open_in_mpv.Player ] - name: [ string ] - executable: [ string ] - fullscreen: [ string ] - pip: [ string ] - enqueue: [ string ] - new_window: [ string ] - needs_ipc: [ true | false ] - flag_overrides: [ map[string]string ] +fake: # open_in_mpv.Player + name: # string + executable: # string + fullscreen: # string + pip: # string + enqueue: # string + new_window: # string + needs_ipc: # true | false + supported_protocols: # []string + flag_overrides: # map[string]string ``` -> See [the default configuration](config.yml) as an example +> See [the default configuration](config.yml) or the [example](#example) below And the `open_in_mpv.Player` object is defined as follows: -| Key | Example value | Description | -|---------------|----------------------------------------|--------------| -| `name` | `mpv` | Full name of the video player; not used internally | -| `executable` | `mpv` | The player's binary path/name (doesn't need full path if already in `$PATH`) | -| `fullscreen` | `"--fs"` | Flag override to open the player in fullscreen (can be empty) | -| `pip` | `"--pip"` | Flag override to open the player in picture-in-picture mode (can be empty) | -| `enqueue` | `"--enqueue"` | Flag override to add the video to the player's queue (can be empty) | -| `new_window` | `"--new-window"` | Flag override to force open a new player window with the video (can be empty) | -| `needs_ipc` | `false` | Controls whether the player needs IPC communication (only generates mpv-compatible JSON commands, used for enqueing videos) | -| `flag_overrides` | `"*": "--mpv-options=%s"` | Defines arbitrary text overrides for command line flags (see below) | +| Key | Example value | Description | +| --------------------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------- | +| `name` | `mpv` | Full name of the video player; not used internally | +| `executable` | `mpv` | The player's binary path/name (doesn't need full path if already in `$PATH`) | +| `fullscreen` | `"--fs"` | Flag override to open the player in fullscreen (can be empty) | +| `pip` | `"--pip"` | Flag override to open the player in picture-in-picture mode (can be empty) | +| `enqueue` | `"--enqueue"` | Flag override to add the video to the player's queue (can be empty) | +| `new_window` | `"--new-window"` | Flag override to force open a new player window with the video (can be empty) | +| `needs_ipc` | `false` | Controls whether the player needs IPC communication (only generates mpv-compatible JSON commands, used for enqueing videos) | +| `supported_protocols` | `["http", "https"]` | An arbitrary whitelist of protocols the player supports. See the [relevant section](#supported-protocols) | +| `flag_overrides` | `"*": "--mpv-%s"` | Defines arbitrary text overrides for command line flags (see below) | #### Flag overrides @@ -98,6 +99,11 @@ players: enqueue: "--enqueue" new_window: "" needs_ipc: true + supported_protocols: + - http + - https + - ftp + - ftps flag_overrides: "*": "--mpv-options=%s" ``` @@ -105,7 +111,7 @@ players: ### The `mpv://` protocol `open-in-mpv install-protocol` will create a custom `xdg-open` desktop file with a scheme handler for the `mpv://` protocol. This lets `xdg-open` call `open-in-mpv` with an encoded URI, so that it can be parsed and the information can be relayed to `mpv` - this logic follows how `iina` parses and opens custom URIs with the `iina://` protocol on Mac. `install-protocol.sh` has the same functionality. -Please note that this specification is enforced quite strictly, as the program will error out when: +Please note that this specification is enforced quite strictly, as the program will error out when at least one of the following conditions is true: - The protocol is not `mpv://` - The method/path is not `/open` @@ -113,14 +119,14 @@ Please note that this specification is enforced quite strictly, as the program w The table below is a simple documentation of the URL query keys and values used to let the `open-in-mpv` executable what to do. -| Key | Example value | Description | -|---------------|----------------------------------------|-------------| -| `url` | `https%3A%2F%2Fyoutu.be%2FdQw4w9WgXcQ` | The actual file URL to be played, URL-encoded | -| `full_screen` | `1` | Controls whether the video is played in fullscreen mode | -| `pip` | `1` | Simulates a picture-in-picture mode (only works with mpv for now) | -| `enqueue` | `1` | Adds a video to the queue (see below) | -| `new_window` | `1` | Forcibly starts a video in a new window even if one is already open | -| `player` | `celluloid` | Starts any supported video player (see [Player support](#player-support)) | +| Key | Example value | Description | +| ------------- | -------------------------------------- | ------------------------------------------------------------------------------ | +| `url` | `https%3A%2F%2Fyoutu.be%2FdQw4w9WgXcQ` | The actual file URL to be played, URL-encoded | +| `full_screen` | `1` | Controls whether the video is played in fullscreen mode | +| `pip` | `1` | Simulates a picture-in-picture mode (only works with mpv for now) | +| `enqueue` | `1` | Adds a video to the queue (see below) | +| `new_window` | `1` | Forcibly starts a video in a new window even if one is already open | +| `player` | `celluloid` | Starts any supported video player (see [Player support](#player-support)) | | `flags` | `--vo%3Dgpu` | Custom command options and flags to be passed to the video player, URL-encoded | ### Playlist and `enqueue` functionality @@ -131,4 +137,7 @@ input-ipc-server=/tmp/mpvsocket ``` ### Player support -Supported players are defined in `config.yml`, where the struct `Player` ([see `config.go`](config.go)) defines supported functionality and command line flag overrides. To request support for a player you're welcome to open a new issue or a pull request or just add your own in your configuration file. \ No newline at end of file +Supported players are defined in `config.yml`, where the struct `Player` ([see `config.go`](config.go)) defines supported functionality and command line flag overrides. To request support for a player you're welcome to open a new issue or a pull request or just add your own in your configuration file. + +### Supported protocols +Since opening an arbitrary URL with a shell command can cause remote code execution on the host machine (for example by loading arbitrary `.so` files on a player by using special [schemes](https://en.wikipedia.org/wiki/List_of_URI_schemes)), only protocols/[schemes](https://en.wikipedia.org/wiki/List_of_URI_schemes) explicitly specified in the configuration will be processed by the native binary without errors. Defaults to `["http", "https"]` if empty. There is also no special instructions parsing or catch-all values. \ No newline at end of file diff --git a/config.go b/config.go index e9ad3ce..cbd6b02 100644 --- a/config.go +++ b/config.go @@ -28,6 +28,9 @@ type Player struct { NewWindow string `yaml:"new_window"` // Controls whether this player needs IPC command to enqueue videos NeedsIpc bool `yaml:"needs_ipc"` + // Controls which (video URL) schemes are to be opened by the current + // player. There is no match-all, each protocol has to be manuall specified + SupportedSchemes []string `yaml:"supported_protocols"` // Overrides for any generic flag FlagOverrides map[string]string `yaml:"flag_overrides"` } @@ -37,6 +40,11 @@ type Config struct { Players map[string]Player } +var defaultSupportedSchemas = []string{ + "http", + "https", +} + var defaultConfig = Config{ Players: map[string]Player{ "mpv": { @@ -52,7 +60,8 @@ var defaultConfig = Config{ }, } -// Tries to load configuration file with fallback +// Tries to load configuration file with fallback to a default configuration +// object func LoadConfig() error { confDirs := configdir.New("", "open-in-mpv") confDirs.LocalPath, _ = filepath.Abs(".") @@ -68,11 +77,25 @@ func LoadConfig() error { return err } - return yaml.Unmarshal(data, &defaultConfig) + err = yaml.Unmarshal(data, &defaultConfig) + if err != nil { + return err + } + + // If the player has no external configuration, use strict defaults + for name, player := range defaultConfig.Players { + if len(player.SupportedSchemes) == 0 { + log.Printf("Player '%s' has no schemas, setting to defaults", player.Name) + player.SupportedSchemes = defaultSupportedSchemas + defaultConfig.Players[name] = player + } + } + + return nil } // Returns player information for the given name if present, otherwise nil -func GetPlayerInfo(name string) *Player { +func GetPlayerConfig(name string) *Player { lowerName := strings.ToLower(name) if p, ok := defaultConfig.Players[lowerName]; ok { return &p diff --git a/extension/Chrome/background.html b/extension/Chrome/background.html index adccbe1..d6540a0 100644 --- a/extension/Chrome/background.html +++ b/extension/Chrome/background.html @@ -1,14 +1,17 @@ +
- - - -