aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--include/VideoPlayer.hpp3
-rw-r--r--mpv/input.conf1
-rw-r--r--mpv/scripts/mordenx.lua10
-rwxr-xr-xrun.sh4
-rw-r--r--src/QuickMedia.cpp16
-rw-r--r--src/VideoPlayer.cpp49
-rw-r--r--video_player/README.md27
-rw-r--r--video_player/src/main.cpp34
9 files changed, 113 insertions, 33 deletions
diff --git a/README.md b/README.md
index ea274d8..c496104 100644
--- a/README.md
+++ b/README.md
@@ -68,7 +68,7 @@ Type text and then wait and QuickMedia will automatically search.\
### Video controls
`mpv` controls apply in general, see https://mpv.io/manual/master/#interactive-control.\
`Esc`/`Backspace`/`Q`: Close the video.\
-`Ctrl+F`: Toggle between fullscreen mode and window mode. `Esc` can also be used to switch from fullscreen mode to window mode.\
+`Ctrl+F`: Toggle between fullscreen mode and window mode.\
`Ctrl+R`: Show pages related to the video, such as comments, related videos or channel videos (if supported).\
`Ctrl+S`: Save the video/music.\
`Ctrl+C`: Copy the url of the currently playing video to the clipboard (with timestamp, if supported).\
diff --git a/include/VideoPlayer.hpp b/include/VideoPlayer.hpp
index feede37..981c114 100644
--- a/include/VideoPlayer.hpp
+++ b/include/VideoPlayer.hpp
@@ -8,7 +8,7 @@
#include <X11/Xlib.h>
namespace QuickMedia {
- using EventCallbackFunc = std::function<void(const char *event_name)>;
+ using EventCallbackFunc = std::function<void(const char *event_name, const std::vector<std::string> &args)>;
using VideoPlayerWindowCreateCallback = std::function<void(mgl::WindowHandle window)>;
// Currently this video player launches mpv and embeds it into the QuickMedia window
@@ -65,6 +65,7 @@ namespace QuickMedia {
// Returns time in seconds
Error get_time_in_file(double *result);
Error add_subtitle(const std::string &url, const std::string &title, const std::string &lang);
+ Error cycle_fullscreen();
int exit_status;
private:
diff --git a/mpv/input.conf b/mpv/input.conf
index 635a82c..26b7ef6 100644
--- a/mpv/input.conf
+++ b/mpv/input.conf
@@ -1,5 +1,6 @@
Ctrl+c ignore
Ctrl+s ignore
+f ignore
BS ignore
q ignore
WHEEL_UP ignore
diff --git a/mpv/scripts/mordenx.lua b/mpv/scripts/mordenx.lua
index 1b6bd5a..2df72c3 100644
--- a/mpv/scripts/mordenx.lua
+++ b/mpv/scripts/mordenx.lua
@@ -114,9 +114,9 @@ local osc_styles = {
SeekbarBg = '{\\blur0\\bord0\\1c&HFFFFFF&}',
SeekbarFg = '{\\blur1\\bord1\\1c&HE39C42&}',
Ctrl1 = '{\\blur0\\bord0\\1c&HFFFFFF&\\3c&HFFFFFF&\\fs36\\fnmaterial-design-iconic-font}',
- Ctrl2 = '{\\blur0\\bord0\\1c&HFFFFFF&\\3c&HFFFFFF&\\fs24\\fnmaterial-design-iconic-font}',
- Ctrl2Flip = '{\\blur0\\bord0\\1c&HFFFFFF&\\3c&HFFFFFF&\\fs24\\fnmaterial-design-iconic-font\\fry180',
- Ctrl3 = '{\\blur0\\bord0\\1c&HFFFFFF&\\3c&HFFFFFF&\\fs24\\fnmaterial-design-iconic-font}',
+ Ctrl2 = '{\\blur0\\bord0\\1c&HFFFFFF&\\3c&HFFFFFF&\\fs30\\fnmaterial-design-iconic-font}',
+ Ctrl2Flip = '{\\blur0\\bord0\\1c&HFFFFFF&\\3c&HFFFFFF&\\fs30\\fnmaterial-design-iconic-font\\fry180',
+ Ctrl3 = '{\\blur0\\bord0\\1c&HFFFFFF&\\3c&HFFFFFF&\\fs30\\fnmaterial-design-iconic-font}',
Time = '{\\blur0\\bord0\\1c&HFFFFFF&\\3c&H000000&\\fs20\\fn' .. user_opts.font .. '}',
Tooltip = '{\\blur1\\bord0.5\\1c&HFFFFFF&\\3c&H000000&\\fs18\\fn' .. user_opts.font .. '}',
Title = '{\\blur1\\bord0.5\\1c&HFFFFFF&\\3c&H0\\fs32\\q2\\fn' .. user_opts.font .. '}',
@@ -1098,7 +1098,7 @@ layouts = function ()
osc_param.areas = {} -- delete areas
-- area for active mouse input
- add_area('input', get_hitbox_coords(posX, posY, 1, osc_geo.w, 104))
+ add_area('input', get_hitbox_coords(posX, posY, 1, osc_geo.w, 113))
-- area for show/hide
add_area('showhide', 0, 0, osc_param.playresx, osc_param.playresy)
@@ -1489,7 +1489,7 @@ function osc_init()
end
ne.visible = (osc_param.playresx >= 540)
ne.eventresponder['mbtn_left_up'] =
- function () mp.commandv('cycle', 'fullscreen') end
+ function () mp.commandv("cycle", "fullscreen") end
--tog_info
ne = new_element('tog_info', 'button')
diff --git a/run.sh b/run.sh
index d9ad3d3..cb82eb5 100755
--- a/run.sh
+++ b/run.sh
@@ -1,6 +1,6 @@
#!/bin/sh -e
-[ $# -ne 1 ] && echo "usage: run.sh debug|release" && exit 1
+[ $# -lt 1 ] && echo "usage: run.sh debug|release <args...>" && exit 1
script_dir=$(dirname "$0")
cd "$script_dir"
@@ -9,4 +9,4 @@ sibs build --"$1" video_player
sibs build --"$1"
echo "Successfully built the video player and QuickMedia"
-"./sibs-build/$(sibs platform)/$1/quickmedia"
+"./sibs-build/$(sibs platform)/$1/quickmedia" "${@:2}"
diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp
index 8d6e4a2..ddb81a9 100644
--- a/src/QuickMedia.cpp
+++ b/src/QuickMedia.cpp
@@ -3076,7 +3076,7 @@ namespace QuickMedia {
std::string channel_url;
AsyncTask<void> related_videos_task;
- std::function<void(const char*)> video_event_callback;
+ EventCallbackFunc video_event_callback;
bool go_to_previous_page = false;
std::string video_url;
@@ -3317,7 +3317,7 @@ namespace QuickMedia {
}
};
- video_event_callback = [&](const char *event_name) mutable {
+ video_event_callback = [&](const char *event_name, const std::vector<std::string> &args) mutable {
if(strcmp(event_name, "pause") == 0) {
//double time_remaining = 9999.0;
//if(video_player->get_time_remaining(&time_remaining) == VideoPlayer::Error::OK && time_remaining <= 1.0)
@@ -3337,6 +3337,8 @@ namespace QuickMedia {
} else if(strcmp(event_name, "seek") == 0) {
if(video_page->is_local())
update_time_pos = true;
+ } else if(strcmp(event_name, "fullscreen") == 0 && args.size() == 1) {
+ window_set_fullscreen(disp, window.get_system_handle(), args[0] == "yes" ? WindowFullscreenState::SET : WindowFullscreenState::UNSET);
}
//fprintf(stderr, "event name: %s\n", event_name);
@@ -3376,13 +3378,12 @@ namespace QuickMedia {
} else if(event.type == mgl::Event::KeyPressed && (event.key.code == mgl::Keyboard::Escape || event.key.code == mgl::Keyboard::Q || event.key.code == mgl::Keyboard::Backspace)) {
// To be able to close the video player while the video is loading
if(window_is_fullscreen(disp, window.get_system_handle())) {
- window_set_fullscreen(disp, window.get_system_handle(), WindowFullscreenState::UNSET);
+ if(video_player && video_player_window && event.key.code != mgl::Keyboard::Escape)
+ video_player->cycle_fullscreen();
} else {
current_page = previous_page;
go_to_previous_page = true;
}
- } else if(event.type == mgl::Event::KeyPressed && event.key.code == mgl::Keyboard::F && event.key.control) {
- window_set_fullscreen(disp, window.get_system_handle(), WindowFullscreenState::TOGGLE);
} else if(event.type == mgl::Event::KeyPressed && event.key.code == mgl::Keyboard::C && event.key.control && !video_page->is_local()) {
save_video_url_to_clipboard();
} else if(event.type == mgl::Event::KeyPressed && event.key.code == mgl::Keyboard::F5 && !video_page->is_local()) {
@@ -3401,14 +3402,15 @@ namespace QuickMedia {
window.close();
} else if(pressed_keysym == XK_Escape || pressed_keysym == XK_q || pressed_keysym == XK_BackSpace) {
if(window_is_fullscreen(disp, window.get_system_handle())) {
- window_set_fullscreen(disp, window.get_system_handle(), WindowFullscreenState::UNSET);
+ if(pressed_keysym != XK_Escape)
+ video_player->cycle_fullscreen();
} else {
current_page = previous_page;
go_to_previous_page = true;
break;
}
} else if(pressed_keysym == XK_f && pressing_ctrl) {
- window_set_fullscreen(disp, window.get_system_handle(), WindowFullscreenState::TOGGLE);
+ video_player->cycle_fullscreen();
} else if(pressed_keysym == XK_s && pressing_ctrl && !video_page->is_local()) {
video_page_download_video(video_page->get_download_url(video_get_max_height()), video_player_window);
} else if(pressed_keysym == XK_F5 && !video_page->is_local()) {
diff --git a/src/VideoPlayer.cpp b/src/VideoPlayer.cpp
index 2c0fe44..26e2013 100644
--- a/src/VideoPlayer.cpp
+++ b/src/VideoPlayer.cpp
@@ -96,8 +96,8 @@ namespace QuickMedia {
video_process_id(-1),
connect_tries(0),
find_window_tries(0),
- event_callback(_event_callback),
- window_create_callback(_window_create_callback),
+ event_callback(std::move(_event_callback)),
+ window_create_callback(std::move(_window_create_callback)),
window_handle(0),
display(nullptr),
request_id_counter(1),
@@ -364,6 +364,21 @@ namespace QuickMedia {
return Error::OK;
}
+ static std::vector<std::string> json_array_to_string_list(const Json::Value &json) {
+ std::vector<std::string> result;
+ if(!json.isArray())
+ return result;
+
+ for(const Json::Value &item : json) {
+ if(!item.isString())
+ continue;
+
+ result.push_back(item.asString());
+ }
+
+ return result;
+ }
+
VideoPlayer::Error VideoPlayer::read_ipc_func() {
Json::Value json_root;
Json::CharReaderBuilder json_builder;
@@ -386,18 +401,26 @@ namespace QuickMedia {
if(json_reader->parse(buffer + start, buffer + i, &json_root, &json_errors) && json_root.isObject()) {
const Json::Value &event = json_root["event"];
- const Json::Value &request_id_json = json_root["request_id"];
+ const Json::Value &args = json_root["args"];
if(event.isString()) {
if(event_callback)
- event_callback(event.asCString());
+ event_callback(event.asCString(), json_array_to_string_list(args));
}
+ const Json::Value &request_id_json = json_root["request_id"];
if(expected_request_id != 0 && request_id_json.isNumeric() && request_id_json.asUInt() == expected_request_id) {
const Json::Value &status_json = json_root["status"];
- if(!status_json.isString() || strcmp(status_json.asCString(), "error") == 0)
+ if(!status_json.isString() || strcmp(status_json.asCString(), "error") == 0) {
response_data_status = ResponseDataStatus::ERROR;
- else
+ const char *err_msg = "Unknown";
+ const Json::Value &message_json = json_root["message"];
+ if(message_json.isString())
+ err_msg = message_json.asCString();
+
+ fprintf(stderr, "VideoPlayer::send_command failed, error from video player: %s\n", err_msg);
+ } else {
response_data_status = ResponseDataStatus::OK;
+ }
request_response_data = json_root["data"];
}
} else {
@@ -440,6 +463,14 @@ namespace QuickMedia {
return send_command(json_root, &result, Json::ValueType::nullValue);
}
+ VideoPlayer::Error VideoPlayer::cycle_fullscreen() {
+ Json::Value json_root(Json::objectValue);
+ json_root["command"] = "cycle-fullscreen";
+
+ Json::Value result;
+ return send_command(json_root, &result, Json::ValueType::nullValue);
+ }
+
uint32_t VideoPlayer::get_next_request_id() {
unsigned int cmd_request_id = request_id_counter;
++request_id_counter;
@@ -483,12 +514,6 @@ namespace QuickMedia {
else
err = Error::READ_INCORRECT_TYPE;
} else if(response_data_status == ResponseDataStatus::ERROR) {
- const char *err_msg = "Unknown";
- const Json::Value &message_json = request_response_data["message"];
- if(message_json.isString())
- err_msg = message_json.asCString();
-
- fprintf(stderr, "VideoPlayer::send_command failed, error from video player: %s\n", err_msg);
err = Error::READ_RESPONSE_ERROR;
goto cleanup;
} else {
diff --git a/video_player/README.md b/video_player/README.md
index 9a74c9c..0d0adeb 100644
--- a/video_player/README.md
+++ b/video_player/README.md
@@ -56,9 +56,34 @@ Add a subtitle file/url that is loaded asynchronously
"request_id": 233 // Optional. Its provided if request_id was provided in the request
}
```
+## cycle-fullscreen
+Return seeking position in file in seconds
+### request
+```
+{
+ "command": "cycle-fullscreen",
+ "request_id": 232 // Optional
+}
+```
+### response on success
+```
+{
+ "status": "success",
+ "request_id": 232, // Optional. Its provided if request_id was provided in the request
+}
+```
+### response on error
+```
+{
+ "status": "error",
+ "message": "error message",
+ "request_id": 233 // Optional. Its provided if request_id was provided in the request
+}
+```
# IPC event
```
{
- "event": "file-loaded"
+ "event": "file-loaded",
+ "args": [] // A list of strings
}
``` \ No newline at end of file
diff --git a/video_player/src/main.cpp b/video_player/src/main.cpp
index 03acd93..33c4d96 100644
--- a/video_player/src/main.cpp
+++ b/video_player/src/main.cpp
@@ -101,6 +101,20 @@ static Json::Value handle_json_command_sub_add(mpv_handle *mpv_ctx, const Json::
return response_json;
}
+static Json::Value handle_json_command_cycle_fullscreen(mpv_handle *mpv_ctx) {
+ const char *args[] = { "cycle", "fullscreen", nullptr };
+ const int res = mpv_command_async(mpv_ctx, 0, args);
+
+ Json::Value response_json(Json::objectValue);
+ if(res < 0) {
+ response_json["status"] = "error";
+ response_json["message"] = mpv_error_string(res);
+ } else {
+ response_json["status"] = "success";
+ }
+ return response_json;
+}
+
static void send_error(const std::string &err_msg, std::optional<int64_t> request_id, int fd) {
fprintf(stderr, "Error: %s\n", err_msg.c_str());
@@ -151,10 +165,12 @@ static void handle_json_command(mpv_handle *mpv_ctx, const Json::Value &json_roo
response_json = handle_json_command_time_pos(mpv_ctx);
} else if(strcmp(command_json.asCString(), "sub-add") == 0) {
response_json = handle_json_command_sub_add(mpv_ctx, json_root);
+ } else if(strcmp(command_json.asCString(), "cycle-fullscreen") == 0) {
+ response_json = handle_json_command_cycle_fullscreen(mpv_ctx);
} else {
response_json = Json::Value(Json::objectValue);
response_json["status"] = "error";
- response_json["message"] = "invalid command " + command_json.asString() + ", expected time-pos or sub-add";
+ response_json["message"] = "invalid command " + command_json.asString() + ", expected time-pos, sub-add or cycle-fullscreen";
}
if(request_id)
@@ -193,9 +209,16 @@ static void handle_request_commands_line_by_line(mpv_handle *mpv_ctx, int fd, ch
command_buffer_size = 0;
}
-static void send_event(const char *event_name, int fd) {
+static void send_event(const char *event_name, int fd, const std::vector<std::string> &args = {}) {
Json::Value json_root(Json::objectValue);
json_root["event"] = event_name;
+ if(!args.empty()) {
+ Json::Value args_json(Json::arrayValue);
+ for(const std::string &arg : args) {
+ args_json.append(arg);
+ }
+ json_root["args"] = std::move(args_json);
+ }
Json::StreamWriterBuilder builder;
builder["commentStyle"] = "None";
@@ -292,6 +315,7 @@ int main(int argc, char **argv) {
check_error(mpv_command(mpv_ctx, cmd), "loadfile");
check_error(mpv_observe_property(mpv_ctx, 0, "idle-active", MPV_FORMAT_FLAG), "observe idle-active");
+ check_error(mpv_observe_property(mpv_ctx, 0, "fullscreen", MPV_FORMAT_FLAG), "observe fullscreen");
char command_buffer[COMMAND_BUFFER_MAX_SIZE];
size_t command_buffer_size = 0;
@@ -325,12 +349,14 @@ int main(int argc, char **argv) {
} else if(event->event_id == MPV_EVENT_SHUTDOWN) {
running = false;
break;
- } else if(event->event_id == MPV_EVENT_PROPERTY_CHANGE && file_started) {
+ } else if(event->event_id == MPV_EVENT_PROPERTY_CHANGE) {
// End of file (idle)
mpv_event_property *property = (mpv_event_property*)event->data;
- if(strcmp(property->name, "idle-active") == 0 && *(int*)property->data == 1) {
+ if(file_started && strcmp(property->name, "idle-active") == 0 && *(int*)property->data == 1) {
running = false;
break;
+ } else if(args.ipc_fd && strcmp(property->name, "fullscreen") == 0) {
+ send_event("fullscreen", args.ipc_fd_num, { *(bool*)property->data ? "yes" : "no" });
}
}