Fully implemented flag overriding and player specification in players.hpp, fixed bugs and updated README
This commit is contained in:
5
Makefile
5
Makefile
@@ -27,4 +27,7 @@ firefox:
|
|||||||
clean:
|
clean:
|
||||||
@rm -f open-in-mpv Firefox.zip Chrome.crx
|
@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
|
23
README.md
23
README.md
@@ -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).
|
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).
|
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
|
## Installation
|
||||||
> Compiled binaries and packed extensions can be found in the [releases page](https://github.com/Baldomo/open-in-mpv/releases).
|
> 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
|
### 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.
|
`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 |
|
| 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) |
|
| `pip` | `1` | Simulates a picture-in-picture mode (only works with mpv for now) |
|
||||||
| `enqueue` | `1` | Adds a video to the queue (see below) |
|
| `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 |
|
| `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 |
|
| `flags` | `--vo%3Dgpu` | Custom command options and flags to be passed to the video player, URL-encoded |
|
||||||
|
|
||||||
### Playlist and `enqueue` functionality
|
### Playlist and `enqueue` functionality
|
||||||
@@ -32,4 +44,7 @@ For `enqueue` to work properly with any mpv-based player (provided it supports m
|
|||||||
|
|
||||||
```conf
|
```conf
|
||||||
input-ipc-server=/tmp/mpvsocket
|
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.
|
@@ -61,7 +61,7 @@ int main(int argc, char const *argv[]) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "Error writing to socket, opening new instance"
|
std::cerr << "Error writing to socket, opening new instance"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
std::system(mo->build_cmd().c_str());
|
std::system(mo->build_cmd().c_str());
|
||||||
|
@@ -3,12 +3,35 @@
|
|||||||
#include "players.hpp"
|
#include "players.hpp"
|
||||||
#include "url.hpp"
|
#include "url.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
using std::string;
|
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 {
|
namespace oim {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -27,6 +50,11 @@ class options {
|
|||||||
bool enqueue_;
|
bool enqueue_;
|
||||||
bool new_window_;
|
bool new_window_;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parses flag overrides and returns the final flags
|
||||||
|
*/
|
||||||
|
string override_flags();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/*
|
/*
|
||||||
* Constructor for oim::options
|
* Constructor for oim::options
|
||||||
@@ -73,12 +101,16 @@ string options::build_cmd() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret << player_info_->executable << " ";
|
ret << player_info_->executable << " ";
|
||||||
if (fullscreen_)
|
if (fullscreen_ && !player_info_->fullscreen.empty())
|
||||||
ret << player_info_->fullscreen << " ";
|
ret << player_info_->fullscreen << " ";
|
||||||
if (pip_)
|
if (pip_ && !player_info_->pip.empty())
|
||||||
ret << player_info_->pip << " ";
|
ret << player_info_->pip << " ";
|
||||||
if (!flags_.empty())
|
if (!flags_.empty()) {
|
||||||
ret << flags_ << " ";
|
if (!player_info_->flag_overrides.empty())
|
||||||
|
ret << override_flags() << " ";
|
||||||
|
else
|
||||||
|
ret << flags_ << " ";
|
||||||
|
}
|
||||||
ret << url_;
|
ret << url_;
|
||||||
|
|
||||||
return ret.str();
|
return ret.str();
|
||||||
@@ -99,6 +131,41 @@ string options::build_ipc() {
|
|||||||
return ret.str();
|
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) {
|
void options::parse(const char *url_s) {
|
||||||
oim::url u(url_s);
|
oim::url u(url_s);
|
||||||
|
|
||||||
@@ -119,15 +186,12 @@ void options::parse(const char *url_s) {
|
|||||||
if (player_info_ == nullptr)
|
if (player_info_ == nullptr)
|
||||||
throw string("Unsupported player: ") + player_;
|
throw string("Unsupported player: ") + player_;
|
||||||
|
|
||||||
fullscreen_ = u.query_value("fullscreen") == "1";
|
fullscreen_ = u.query_value("full_screen") == "1";
|
||||||
pip_ = u.query_value("pip") == "1";
|
pip_ = u.query_value("pip") == "1";
|
||||||
enqueue_ = u.query_value("enqueue") == "1";
|
enqueue_ = u.query_value("enqueue") == "1";
|
||||||
new_window_ = u.query_value("new_window") == "1";
|
new_window_ = u.query_value("new_window") == "1";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool options::needs_ipc() {
|
bool options::needs_ipc() { return player_info_->needs_ipc; }
|
||||||
// For now this is needed only when queuing videos
|
|
||||||
return enqueue_;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace oim
|
} // namespace oim
|
@@ -27,17 +27,20 @@ struct player {
|
|||||||
bool needs_ipc;
|
bool needs_ipc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
* Overrides for any extra command line flag
|
||||||
|
*
|
||||||
* Override syntax:
|
* Override syntax:
|
||||||
* `"*"`: matches anything and will take precedence over any other
|
* `"*"`: 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`
|
* `"flag"`: matches the flag `--flag`
|
||||||
* e.g. the pair `{"foo", "bar"}` will replace `--foo` with
|
* e.g. the pair `{"--foo", "--bar"}` will replace `--foo` with
|
||||||
* `--bar`
|
* `--bar`
|
||||||
* `"%s"`: is replaced with the original flag without the leading `--`
|
* `"%s"`: is replaced with the original flag without the leading `--`
|
||||||
* e.g. the pair `{"foo", "--%s-bar"}` will replace `--foo` with
|
* e.g. the pair `{"--foo", "--%s-bar"}` will replace `--foo` with
|
||||||
* `--foo-bar`
|
* `--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
|
* considered a flags as a whole
|
||||||
*/
|
*/
|
||||||
unordered_map<string, string> flag_overrides;
|
unordered_map<string, string> flag_overrides;
|
||||||
@@ -61,7 +64,7 @@ unordered_map<string, player> player_info = {
|
|||||||
.enqueue = "--enqueue",
|
.enqueue = "--enqueue",
|
||||||
.new_window = "--new-window",
|
.new_window = "--new-window",
|
||||||
.needs_ipc = false,
|
.needs_ipc = false,
|
||||||
.flag_overrides = { { "*", "--mpv-options=%s" } } } }
|
.flag_overrides = { { "*", "--mpv-options=%s" } } } },
|
||||||
};
|
};
|
||||||
|
|
||||||
player *get_player_info(string name) {
|
player *get_player_info(string name) {
|
||||||
|
Reference in New Issue
Block a user