Fully implemented flag overriding and player specification in players.hpp, fixed bugs and updated README

This commit is contained in:
Baldomo
2021-01-24 18:44:12 +01:00
parent 93f7bc29f3
commit 1bf066ec7c
5 changed files with 107 additions and 22 deletions

View File

@@ -27,4 +27,7 @@ firefox:
clean:
@rm -f open-in-mpv Firefox.zip Chrome.crx
.PHONY: all release debug install uninstall firefox clean
fmt:
clang-format -i src/*.{hpp,cpp}
.PHONY: all release debug install uninstall firefox clean fmt

View File

@@ -1,8 +1,14 @@
# open-in-mpv
<h1 align="center">open-in-mpv</h1>
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 C++20 (this is a rewrite from Rust).
- [Installation](#installation)
- [The `mpv://` protocol](#the-mpv-protocol)
- [Playlist and `enqueue` functionality](#playlist-and-enqueue-functionality)
- [Player support](#player-support)
## Installation
> Compiled binaries and packed extensions can be found in the [releases page](https://github.com/Baldomo/open-in-mpv/releases).
@@ -15,7 +21,13 @@ sudo make install
### 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.
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:
Please note that this specification is enforced quite strictly, as the program will error out when:
- The protocol is not `mpv://`
- The method/path is not `/open`
- The query is empty
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 |
|---------------|----------------------------------------|---------------|
@@ -24,7 +36,7 @@ The table below is a simple documentation of the URL query keys and values used
| `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 arbitrary video player (only mpv-based ones are recommended, such as [Celluloid](https://celluloid-player.github.io/)) |
| `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
@@ -32,4 +44,7 @@ For `enqueue` to work properly with any mpv-based player (provided it supports m
```conf
input-ipc-server=/tmp/mpvsocket
```
```
### Player support
Supported players are defined in `src/players.hpp`, where the struct `player` 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.

View File

@@ -61,7 +61,7 @@ int main(int argc, char const *argv[]) {
return 0;
}
std::cout << "Error writing to socket, opening new instance"
std::cerr << "Error writing to socket, opening new instance"
<< std::endl;
}
std::system(mo->build_cmd().c_str());

View File

@@ -3,12 +3,35 @@
#include "players.hpp"
#include "url.hpp"
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <string>
#include <vector>
using std::string;
namespace {
// Replace all occurrences of `from` with `to` in `str`
string replace_all(string str, const string &from, const string &to) {
size_t start_pos = 0;
while ((start_pos = str.find(from, start_pos)) != string::npos) {
str.replace(start_pos, from.length(), to);
// Handles case where 'to' is a substring of 'from'
start_pos += to.length();
}
return str;
}
// Remove all characters equals to `c` at the beginning of the string
string lstrip(string str, char c) {
while (str.at(0) == c)
str.replace(0, 1, "");
return str;
}
} // namespace
namespace oim {
/*
@@ -27,6 +50,11 @@ class options {
bool enqueue_;
bool new_window_;
/*
* Parses flag overrides and returns the final flags
*/
string override_flags();
public:
/*
* Constructor for oim::options
@@ -73,12 +101,16 @@ string options::build_cmd() {
}
ret << player_info_->executable << " ";
if (fullscreen_)
if (fullscreen_ && !player_info_->fullscreen.empty())
ret << player_info_->fullscreen << " ";
if (pip_)
if (pip_ && !player_info_->pip.empty())
ret << player_info_->pip << " ";
if (!flags_.empty())
ret << flags_ << " ";
if (!flags_.empty()) {
if (!player_info_->flag_overrides.empty())
ret << override_flags() << " ";
else
ret << flags_ << " ";
}
ret << url_;
return ret.str();
@@ -99,6 +131,41 @@ string options::build_ipc() {
return ret.str();
}
string options::override_flags() {
// Return immediatly in case there are no overrides
if (player_info_->flag_overrides.empty())
return flags_;
bool star = false;
std::ostringstream ret;
// Check whether there's a global override
auto star_pair = player_info_->flag_overrides.find("*");
if (star_pair != player_info_->flag_overrides.end())
star = true;
// Turn flags_ into a stream to tokenize somewhat idiomatically
auto flagstream = std::istringstream{ flags_ };
string tmp;
while (flagstream >> tmp) {
if (star) {
// Remove all dashes at the beginning of the flag
string stripped = ::lstrip(tmp, '-');
ret << ::replace_all((*star_pair).second, "%s", stripped);
} else {
// Search for the flag currently being processed
auto fo = player_info_->flag_overrides.find(tmp);
if (fo == player_info_->flag_overrides.end())
continue;
ret << ::replace_all((*fo).second, "%s", tmp);
}
}
return ret.str();
}
void options::parse(const char *url_s) {
oim::url u(url_s);
@@ -119,15 +186,12 @@ void options::parse(const char *url_s) {
if (player_info_ == nullptr)
throw string("Unsupported player: ") + player_;
fullscreen_ = u.query_value("fullscreen") == "1";
fullscreen_ = u.query_value("full_screen") == "1";
pip_ = u.query_value("pip") == "1";
enqueue_ = u.query_value("enqueue") == "1";
new_window_ = u.query_value("new_window") == "1";
}
bool options::needs_ipc() {
// For now this is needed only when queuing videos
return enqueue_;
}
bool options::needs_ipc() { return player_info_->needs_ipc; }
} // namespace oim

View File

@@ -27,17 +27,20 @@ struct player {
bool needs_ipc;
/*
* Overrides for any extra command line flag
*
* Override syntax:
* `"*"`: matches anything and will take precedence over any other
* override e.g. the pair `{"*", ""}` will void all flags
* override
* e.g. the pair `{"*", ""}` will void all flags
* `"flag"`: matches the flag `--flag`
* e.g. the pair `{"foo", "bar"}` will replace `--foo` with
* `--bar`
* e.g. the pair `{"--foo", "--bar"}` will replace `--foo` with
* `--bar`
* `"%s"`: is replaced with the original flag without the leading `--`
* e.g. the pair `{"foo", "--%s-bar"}` will replace `--foo` with
* `--foo-bar`
* e.g. the pair `{"--foo", "--%s-bar"}` will replace `--foo` with
* `--foo-bar`
*
* Note: command line options with parameters such as --foo=bar are
* Note: command line options with parameters such as `--foo=bar` are
* considered a flags as a whole
*/
unordered_map<string, string> flag_overrides;
@@ -61,7 +64,7 @@ unordered_map<string, player> player_info = {
.enqueue = "--enqueue",
.new_window = "--new-window",
.needs_ipc = false,
.flag_overrides = { { "*", "--mpv-options=%s" } } } }
.flag_overrides = { { "*", "--mpv-options=%s" } } } },
};
player *get_player_info(string name) {