From 94d911a0caa79bb207c07e82f74b03db7070232e Mon Sep 17 00:00:00 2001 From: Zhu_Elly Date: Tue, 28 Apr 2026 11:43:50 +0800 Subject: [PATCH 01/64] First commit --- src/server/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/server/main.cpp b/src/server/main.cpp index 102a6a4b..03e5a00a 100644 --- a/src/server/main.cpp +++ b/src/server/main.cpp @@ -600,3 +600,4 @@ int main() { t1.join(); return 0; } + From 4c2783a81751f66ccd51ed91c4d7ab1672b1e213 Mon Sep 17 00:00:00 2001 From: Zhu_Elly Date: Wed, 29 Apr 2026 13:54:54 +0800 Subject: [PATCH 02/64] Test --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 069ba891..e282c4b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_C_STANDARD 17) + # --- NUCLEAR STATIC OVERRIDES (MUST BE AT THE TOP) --- # These must run before ANY include(FetchContent) set(BUILD_SHARED_LIBS OFF CACHE BOOL "Global Static" FORCE) From 7727493be53421d40a549954b3bc52a9c33f26e2 Mon Sep 17 00:00:00 2001 From: Zhu_Elly Date: Wed, 29 Apr 2026 13:56:37 +0800 Subject: [PATCH 03/64] update account --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e282c4b7..069ba891 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,6 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_C_STANDARD 17) - # --- NUCLEAR STATIC OVERRIDES (MUST BE AT THE TOP) --- # These must run before ANY include(FetchContent) set(BUILD_SHARED_LIBS OFF CACHE BOOL "Global Static" FORCE) From 43e05f7fc7cf92e8d5662f95a3126268736cb51e Mon Sep 17 00:00:00 2001 From: Zhu_Elly Date: Wed, 29 Apr 2026 13:57:08 +0800 Subject: [PATCH 04/64] TEST --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 069ba891..e282c4b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_C_STANDARD 17) + # --- NUCLEAR STATIC OVERRIDES (MUST BE AT THE TOP) --- # These must run before ANY include(FetchContent) set(BUILD_SHARED_LIBS OFF CACHE BOOL "Global Static" FORCE) From d057527675e23d3cc0eec8f2f89f7e9b6a7fad0e Mon Sep 17 00:00:00 2001 From: Zhu_Elly Date: Wed, 29 Apr 2026 13:59:23 +0800 Subject: [PATCH 05/64] update --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e282c4b7..069ba891 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,6 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_C_STANDARD 17) - # --- NUCLEAR STATIC OVERRIDES (MUST BE AT THE TOP) --- # These must run before ANY include(FetchContent) set(BUILD_SHARED_LIBS OFF CACHE BOOL "Global Static" FORCE) From 6575d9bc784bf8ee668b3b19523e51b8e00f5d39 Mon Sep 17 00:00:00 2001 From: Zhu_Elly Date: Wed, 29 Apr 2026 14:00:51 +0800 Subject: [PATCH 06/64] dd --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 069ba891..e282c4b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_C_STANDARD 17) + # --- NUCLEAR STATIC OVERRIDES (MUST BE AT THE TOP) --- # These must run before ANY include(FetchContent) set(BUILD_SHARED_LIBS OFF CACHE BOOL "Global Static" FORCE) From 682ac597e2a9053bce8846c0f23e432161b5d5a9 Mon Sep 17 00:00:00 2001 From: Zhu_Elly Date: Wed, 29 Apr 2026 14:01:03 +0800 Subject: [PATCH 07/64] test --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e282c4b7..069ba891 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,6 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_C_STANDARD 17) - # --- NUCLEAR STATIC OVERRIDES (MUST BE AT THE TOP) --- # These must run before ANY include(FetchContent) set(BUILD_SHARED_LIBS OFF CACHE BOOL "Global Static" FORCE) From fffa55fea227bfc18404f9fa1084c57686d12a75 Mon Sep 17 00:00:00 2001 From: Zhu_Elly Date: Wed, 29 Apr 2026 14:02:51 +0800 Subject: [PATCH 08/64] test --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 069ba891..e282c4b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_C_STANDARD 17) + # --- NUCLEAR STATIC OVERRIDES (MUST BE AT THE TOP) --- # These must run before ANY include(FetchContent) set(BUILD_SHARED_LIBS OFF CACHE BOOL "Global Static" FORCE) From f5cee130e4afb9d5501157493ace27afef2cdb42 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Wed, 29 Apr 2026 15:52:09 +0800 Subject: [PATCH 09/64] First commit --- src/server/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/server/main.cpp b/src/server/main.cpp index 03e5a00a..37a9d3d0 100644 --- a/src/server/main.cpp +++ b/src/server/main.cpp @@ -595,6 +595,7 @@ int main() { controller.update(); + t3.join(); t2.join(); t1.join(); From db77e5ed9dcff7e6364e2819d89eb2f48054e898 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Wed, 29 Apr 2026 15:58:46 +0800 Subject: [PATCH 10/64] Update find camera method --- src/master/GoProMaster.cpp | 17 ++--------------- src/master/GoProMaster.h | 1 - src/master/popup/add_camera_popwin.cpp | 2 +- src/master/popup/add_preset_popwin.cpp | 2 +- src/master/popup/preview/decode.cpp | 2 +- src/master/popup/preview/preview_popwin.cpp | 4 ++-- src/master/windows/inspector/command.cpp | 2 +- src/master/windows/inspector/inspector.cpp | 2 +- src/master/windows/inspector/media.cpp | 2 +- src/master/windows/inspector/setting.cpp | 2 +- 10 files changed, 11 insertions(+), 25 deletions(-) diff --git a/src/master/GoProMaster.cpp b/src/master/GoProMaster.cpp index 4d19a3b7..acf4df04 100644 --- a/src/master/GoProMaster.cpp +++ b/src/master/GoProMaster.cpp @@ -674,7 +674,7 @@ void GoProMaster::processMessage(const std::string& server, const std::string& m replaceCameraFromServer(server, ips); for(int32_t i = 0; i < ips.size(); i++){ - int32_t index = findCamera(ips[i]); + int32_t index = findCamera(server, ips[i]); cameras[index]->serial = serial[i]; if(names.count(ips[i])){ cameras[index]->name = names.at(ips[i]); @@ -720,7 +720,7 @@ void GoProMaster::processMessage(const std::string& server, const std::string& m continue; } std::string ip_ref = ip.value()["ip"].get(); - int32_t found = findCamera(ip_ref); + int32_t found = findCamera(server, ip_ref); CameraInfo _cam; if(found == -1){ auto cam = std::make_shared(); @@ -1012,19 +1012,6 @@ std::string GoProMaster::getBarInfo(const std::shared_ptr &c){ return result; } -int32_t GoProMaster::findCamera(const std::string ip){ - int32_t index = 0; - for(const auto& c : cameras){ - if(c){ - if(c->ip == ip){ - return index; - } - } - ++index; - } - return -1; -} - int32_t GoProMaster::findServer(const std::string ip){ int32_t index = 0; for(const auto& c : servers){ diff --git a/src/master/GoProMaster.h b/src/master/GoProMaster.h index 39c93730..03c486a1 100644 --- a/src/master/GoProMaster.h +++ b/src/master/GoProMaster.h @@ -220,7 +220,6 @@ class GoProMaster { bool getStatusFromCamera(CameraInfo target, json& res); std::string getBarInfo(const std::shared_ptr &c); - int32_t findCamera(const std::string ip); int32_t findServer(const std::string ip); int32_t findCamera(const std::string server, const std::string ip); }; diff --git a/src/master/popup/add_camera_popwin.cpp b/src/master/popup/add_camera_popwin.cpp index cc324be2..d4bef4bf 100644 --- a/src/master/popup/add_camera_popwin.cpp +++ b/src/master/popup/add_camera_popwin.cpp @@ -67,7 +67,7 @@ void AddCameraPopup::render(){ error = "Server is disconnected."; pass = false; } - if(master->findCamera(GetRemoteIPBySerial(camera_serial_buf)) != -1){ + if(master->findCamera(server_ip_buf, GetRemoteIPBySerial(camera_serial_buf)) != -1){ error = "Camera already added."; pass = false; } diff --git a/src/master/popup/add_preset_popwin.cpp b/src/master/popup/add_preset_popwin.cpp index ac7913e1..f405934d 100644 --- a/src/master/popup/add_preset_popwin.cpp +++ b/src/master/popup/add_preset_popwin.cpp @@ -45,7 +45,7 @@ void AddPresetPopup::save_preset(){ json status = json::object(); json setting = json::object(); json data = json::object(); - int32_t t = master->findCamera(state->current_camera_item); + int32_t t = master->findCamera(state->current_camera_server, state->current_camera_item); if(t < 0) return; std::lock_guard lock(master->camera_mtx); const std::shared_ptr& c = master->getCameras().at(t); diff --git a/src/master/popup/preview/decode.cpp b/src/master/popup/preview/decode.cpp index eb8f1e95..38098657 100644 --- a/src/master/popup/preview/decode.cpp +++ b/src/master/popup/preview/decode.cpp @@ -17,7 +17,7 @@ void PreviewPopup::update_decoder(){ { std::lock_guard lock(master->camera_mtx); - s = master->findCamera(state->preview_ip); + s = master->findCamera(state->preview_server, state->preview_ip); if(s == -1){ std::cout << "[Preview Decoder] Cannot find camera: " << state->preview_ip << std::endl; diff --git a/src/master/popup/preview/preview_popwin.cpp b/src/master/popup/preview/preview_popwin.cpp index 704adc63..3991b7f5 100644 --- a/src/master/popup/preview/preview_popwin.cpp +++ b/src/master/popup/preview/preview_popwin.cpp @@ -115,7 +115,7 @@ void PreviewPopup::_draw_rotation_button(){ void PreviewPopup::_draw_camera_selection(){ int32_t s = -1; std::lock_guard lock(master->camera_mtx); - s = master->findCamera(state->preview_ip); + s = master->findCamera(state->preview_server, state->preview_ip); if(s != -1){ const std::shared_ptr& c = master->getCameras().at(s); std::string display_name = c->name; @@ -163,7 +163,7 @@ void PreviewPopup::_draw_setting(){ if(setting_drawer != NULL){ int32_t s = -1; std::lock_guard lock(master->camera_mtx); - s = master->findCamera(state->preview_ip); + s = master->findCamera(state->preview_server, state->preview_ip); if(s != -1){ const std::shared_ptr& c = master->getCameras().at(s); if(ImGui::Button("Quick Apply All##Preview_Popwin_Action")){ diff --git a/src/master/windows/inspector/command.cpp b/src/master/windows/inspector/command.cpp index d19bdea0..b08a84e2 100644 --- a/src/master/windows/inspector/command.cpp +++ b/src/master/windows/inspector/command.cpp @@ -5,7 +5,7 @@ void InspectorWindow::draw_command_local(){ ImGui::Text("Single Camera Control"); - int32_t current_camera = master->findCamera(state->current_camera_item); + int32_t current_camera = master->findCamera(state->current_camera_server, state->current_camera_item); bool should_disabled = state->current_camera_item.size() < 10 || current_camera == -1; ImGui::BeginDisabled(should_disabled); diff --git a/src/master/windows/inspector/inspector.cpp b/src/master/windows/inspector/inspector.cpp index c2c789b5..8e82b2fb 100644 --- a/src/master/windows/inspector/inspector.cpp +++ b/src/master/windows/inspector/inspector.cpp @@ -99,7 +99,7 @@ void InspectorWindow::render(){ ImGui::Begin("Inspector", &enable, w_flag); { std::lock_guard lock(master->camera_mtx); - int32_t s = master->findCamera(state->current_camera_item); + int32_t s = master->findCamera(state->current_camera_server, state->current_camera_item); if(s != -1){ auto& c = master->getCameras().at(s); should_disabled = !c->connected || state->current_camera_item.size() < 10 || s == -1 || !state->current_setting_items_bind; diff --git a/src/master/windows/inspector/media.cpp b/src/master/windows/inspector/media.cpp index 29c5961d..a123c99f 100644 --- a/src/master/windows/inspector/media.cpp +++ b/src/master/windows/inspector/media.cpp @@ -38,7 +38,7 @@ void InspectorWindow::draw_media_global(){ ImVec2 button_size = ImVec2(size.x / 2.0F - style.ItemSpacing.x, 0); ImVec2 button3_size = ImVec2(size.x / 3.0F - style.ItemSpacing.x, 0); - int32_t camera_ip = master->findCamera(state->current_camera_item); + int32_t camera_ip = master->findCamera(state->current_camera_server, state->current_camera_item); if(ImGui::InputText("Media Download", &state->current_download_location)){ state->update_server(); } diff --git a/src/master/windows/inspector/setting.cpp b/src/master/windows/inspector/setting.cpp index fc255cc8..48c18d91 100644 --- a/src/master/windows/inspector/setting.cpp +++ b/src/master/windows/inspector/setting.cpp @@ -62,7 +62,7 @@ void InspectorWindow::global_draw_protune(std::shared_ptr& state, s } void InspectorWindow::_draw_setting(std::vector& ordered){ - int32_t current = master->findCamera(state->current_camera_item); + int32_t current = master->findCamera(state->current_camera_server, state->current_camera_item); if(current < 0) return; auto& c = master->getCameras().at(current); int32_t move_from = -1, move_to = -1; From 687aa3561b8eabfaeb795ffed8c7fecea1ed19c0 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Wed, 29 Apr 2026 16:07:11 +0800 Subject: [PATCH 11/64] Fixed master findCamera return probably -1 issue in process message method --- src/master/GoProMaster.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/master/GoProMaster.cpp b/src/master/GoProMaster.cpp index acf4df04..ac5ba579 100644 --- a/src/master/GoProMaster.cpp +++ b/src/master/GoProMaster.cpp @@ -675,9 +675,11 @@ void GoProMaster::processMessage(const std::string& server, const std::string& m for(int32_t i = 0; i < ips.size(); i++){ int32_t index = findCamera(server, ips[i]); - cameras[index]->serial = serial[i]; - if(names.count(ips[i])){ - cameras[index]->name = names.at(ips[i]); + if(index != -1){ + cameras[index]->serial = serial[i]; + if(names.count(ips[i])){ + cameras[index]->name = names.at(ips[i]); + } } } From bb298047240478b93a96d4061b12b62eaaed90c7 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Wed, 29 Apr 2026 16:25:45 +0800 Subject: [PATCH 12/64] update onclose part --- src/server/main.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/server/main.cpp b/src/server/main.cpp index 37a9d3d0..1cb983d4 100644 --- a/src/server/main.cpp +++ b/src/server/main.cpp @@ -488,8 +488,9 @@ void WebsocketServer(){ std::lock_guard lock(broadcast_mtx); printf("Client disconnected: %s\n", channel->peeraddr().c_str()); for(int32_t i = 0; i < hosts.size(); i++){ - bool find = std::strcmp(hosts[i]->get()->peeraddr().c_str(), - channel->peeraddr().c_str()); + const char* host_peeraddr = hosts[i]->get()->peeraddr().c_str(); + const char* channel_peeraddr = channel->peeraddr().c_str(); + bool find = std::strcmp(host_peeraddr, channel_peeraddr); if(find){ hosts.erase(hosts.begin() + i); break; From 476be6c8299208a16a0d7ef3bde2e925a1d0f55c Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Wed, 29 Apr 2026 16:27:11 +0800 Subject: [PATCH 13/64] Remove hosts --- src/server/main.cpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/server/main.cpp b/src/server/main.cpp index 1cb983d4..ba713618 100644 --- a/src/server/main.cpp +++ b/src/server/main.cpp @@ -24,10 +24,6 @@ #include "hv/hsocket.h" #include "GoProController.h" -/// -/// All the master websocket instances -/// -std::vector hosts = std::vector(); /// /// Main worker, HERO is here /// @@ -422,7 +418,6 @@ void WebsocketServer(){ ws.onopen = [&](const WebSocketChannelPtr& channel, const HttpRequestPtr& req) { std::lock_guard lock(broadcast_mtx); printf("Client connected: %s\n", channel->peeraddr().c_str()); - hosts.push_back(&channel); int32_t f = -1; for(int32_t i = 0; i < broadcast_addrs.size(); i++){ @@ -487,15 +482,6 @@ void WebsocketServer(){ ws.onclose = [&](const WebSocketChannelPtr& channel) { std::lock_guard lock(broadcast_mtx); printf("Client disconnected: %s\n", channel->peeraddr().c_str()); - for(int32_t i = 0; i < hosts.size(); i++){ - const char* host_peeraddr = hosts[i]->get()->peeraddr().c_str(); - const char* channel_peeraddr = channel->peeraddr().c_str(); - bool find = std::strcmp(host_peeraddr, channel_peeraddr); - if(find){ - hosts.erase(hosts.begin() + i); - break; - } - } int32_t f = -1; for(int32_t i = 0; i < broadcast_addrs.size(); i++){ From d0c378a38a7b09c5bdb92cd41c9c9a25f96c0fb3 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Wed, 29 Apr 2026 16:36:19 +0800 Subject: [PATCH 14/64] Update replaceCameraFromServer --- src/master/GoProMaster.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/master/GoProMaster.cpp b/src/master/GoProMaster.cpp index ac5ba579..51fa7921 100644 --- a/src/master/GoProMaster.cpp +++ b/src/master/GoProMaster.cpp @@ -905,7 +905,7 @@ void GoProMaster::replaceCameraFromServer(const std::string server, const std::v for (const auto& new_ip : ips) { bool exists = false; for (const auto& existing_cam : cameras) { - if (existing_cam && existing_cam->ip == new_ip) { + if (existing_cam && existing_cam->ip == new_ip && existing_cam->server == server) { exists = true; break; } From 3db64c814e5b5863e25540f17edb9ec517f589ab Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Wed, 29 Apr 2026 17:16:42 +0800 Subject: [PATCH 15/64] First Commit --- src/master/GoProMaster.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/master/GoProMaster.cpp b/src/master/GoProMaster.cpp index 51fa7921..2d69e7ca 100644 --- a/src/master/GoProMaster.cpp +++ b/src/master/GoProMaster.cpp @@ -899,6 +899,7 @@ void GoProMaster::replaceCameraFromServer(const std::string server, const std::v } return false; }); + cameras.erase(it, cameras.end()); // Append part From 1ed72aa0d481397d0a9681717d7f5699d328ba2d Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Thu, 30 Apr 2026 10:00:53 +0800 Subject: [PATCH 16/64] Fixed --- package/deb_master_amd64 | 2 +- package/deb_server_amd64 | 2 +- package/deb_server_arm64 | 2 +- src/master/windows/inspector/filter.cpp | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package/deb_master_amd64 b/package/deb_master_amd64 index 41e1f952..f3034ff3 100644 --- a/package/deb_master_amd64 +++ b/package/deb_master_amd64 @@ -1,5 +1,5 @@ Package: go-pro-control-master -Version: 0.1.3 +Version: 1.0.1 Section: shells Priority: optional Architecture: amd64 diff --git a/package/deb_server_amd64 b/package/deb_server_amd64 index a7a8a8f8..74a673cf 100644 --- a/package/deb_server_amd64 +++ b/package/deb_server_amd64 @@ -1,5 +1,5 @@ Package: go-pro-control-server -Version: 0.1.3 +Version: 1.0.1 Section: shells Priority: optional Architecture: amd64 diff --git a/package/deb_server_arm64 b/package/deb_server_arm64 index 7b4d1437..8cc0fde1 100644 --- a/package/deb_server_arm64 +++ b/package/deb_server_arm64 @@ -1,5 +1,5 @@ Package: go-pro-control-server -Version: 0.1.3 +Version: 1.0.1 Section: shells Priority: optional Architecture: arm64 diff --git a/src/master/windows/inspector/filter.cpp b/src/master/windows/inspector/filter.cpp index 168fb844..7a45edf6 100644 --- a/src/master/windows/inspector/filter.cpp +++ b/src/master/windows/inspector/filter.cpp @@ -264,8 +264,8 @@ bool InspectorWindow::conditional_filter_option(const std::shared_ptr Date: Thu, 30 Apr 2026 10:33:05 +0800 Subject: [PATCH 17/64] Master fixed the process message filter for query:get --- src/master/GoProMaster.cpp | 7 +++++++ src/server/main.cpp | 1 - 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/master/GoProMaster.cpp b/src/master/GoProMaster.cpp index 2d69e7ca..89e4320a 100644 --- a/src/master/GoProMaster.cpp +++ b/src/master/GoProMaster.cpp @@ -694,6 +694,10 @@ void GoProMaster::processMessage(const std::string& server, const std::string& m std::cerr << "query:get, return value should be array" << std::endl; return; } + if(key == "query:get" && data["value"]["data"].size() == 0){ + std::cout << "Camera response null state from server: " << server << std::endl; + return; + } /** * In case you're confuse here... * The data is like this @@ -722,6 +726,9 @@ void GoProMaster::processMessage(const std::string& server, const std::string& m continue; } std::string ip_ref = ip.value()["ip"].get(); + if(ip_ref.size() == 0){ + continue; + } int32_t found = findCamera(server, ip_ref); CameraInfo _cam; if(found == -1){ diff --git a/src/server/main.cpp b/src/server/main.cpp index ba713618..b60bcab7 100644 --- a/src/server/main.cpp +++ b/src/server/main.cpp @@ -383,7 +383,6 @@ void MediaAction(const WebSocketChannelPtr& channel, json j){ } } - void PreviewAction(const WebSocketChannelPtr& channel, json j){ std::string target = ""; std::string name = ""; From a9c0080fbced192ba0edecc8ff09d98d79e847cd Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Thu, 30 Apr 2026 10:41:31 +0800 Subject: [PATCH 18/64] First commit --- src/server/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/server/main.cpp b/src/server/main.cpp index b60bcab7..473feef9 100644 --- a/src/server/main.cpp +++ b/src/server/main.cpp @@ -24,6 +24,7 @@ #include "hv/hsocket.h" #include "GoProController.h" + /// /// Main worker, HERO is here /// From 2feab32473e13c8da7106887a650962f27ccae93 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Thu, 30 Apr 2026 14:11:28 +0800 Subject: [PATCH 19/64] Added keep alive command at last_media query --- src/server/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/server/main.cpp b/src/server/main.cpp index 473feef9..77d9987d 100644 --- a/src/server/main.cpp +++ b/src/server/main.cpp @@ -362,6 +362,7 @@ void MediaAction(const WebSocketChannelPtr& channel, json j){ } if(name == "lastmedia"){ + controller.keep_alive(""); resultText = controller.getLastMedia(target); if(json::accept(resultText)){ r["data"] = json::parse(resultText); From cbe44a83353aa53228ad8d70c3a6ee0bbe3e03a4 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Thu, 30 Apr 2026 14:43:23 +0800 Subject: [PATCH 20/64] Tryinf to fixed FPS issue again.. --- src/master/windows/inspector/filter.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/master/windows/inspector/filter.cpp b/src/master/windows/inspector/filter.cpp index 7a45edf6..2df305ae 100644 --- a/src/master/windows/inspector/filter.cpp +++ b/src/master/windows/inspector/filter.cpp @@ -216,7 +216,7 @@ bool InspectorWindow::conditional_filter_option(const std::shared_ptr Date: Thu, 30 Apr 2026 14:49:12 +0800 Subject: [PATCH 21/64] Update roadmap in readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fdef91e3..ac4f6417 100644 --- a/README.md +++ b/README.md @@ -21,15 +21,15 @@ Tool for control multiple GoPro Cameras, The design is for above 100 cameras con - [x] Preset changer - [x] Monitor cameras information - [x] Modify GoPro Camera Setting - - [ ] Custom preset apply pipeline - - [ ] Sync custom preset setting to all + - [x] Custom preset apply pipeline + - [x] Sync custom preset setting to all * WebCam - [x] Change to WebCam Mode * Preview - [x] Display selected GoPro camera - [x] Change setting while in preview Popup window * Media - - [ ] One click pull latest media file + - [x] One click pull latest media file - [ ] Media Browser for download and modify and delete etc... ## Screenshot From aa10b43d4d496b03eb407e74e334e27d93ebfd19 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Thu, 30 Apr 2026 15:27:29 +0800 Subject: [PATCH 22/64] Added quick apply skipping boolean in server side --- src/master/GoProMaster.cpp | 4 ++++ src/master/GoProMaster.h | 1 + src/master/data/state.h | 1 + src/master/main.cpp | 5 ++++- src/server/GoProController.h | 6 ++++++ src/server/controller/query.cpp | 6 ++++++ src/server/main.cpp | 3 +++ 7 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/master/GoProMaster.cpp b/src/master/GoProMaster.cpp index 89e4320a..b2ea2a66 100644 --- a/src/master/GoProMaster.cpp +++ b/src/master/GoProMaster.cpp @@ -1022,6 +1022,10 @@ std::string GoProMaster::getBarInfo(const std::shared_ptr &c){ return result; } +size_t GoProMaster::getServerCount(){ + return servers.size(); +} + int32_t GoProMaster::findServer(const std::string ip){ int32_t index = 0; for(const auto& c : servers){ diff --git a/src/master/GoProMaster.h b/src/master/GoProMaster.h index 03c486a1..9e5c932d 100644 --- a/src/master/GoProMaster.h +++ b/src/master/GoProMaster.h @@ -220,6 +220,7 @@ class GoProMaster { bool getStatusFromCamera(CameraInfo target, json& res); std::string getBarInfo(const std::shared_ptr &c); + size_t getServerCount(); int32_t findServer(const std::string ip); int32_t findCamera(const std::string server, const std::string ip); }; diff --git a/src/master/data/state.h b/src/master/data/state.h index a6a745cd..cf8db3b6 100644 --- a/src/master/data/state.h +++ b/src/master/data/state.h @@ -19,6 +19,7 @@ enum class InspectorObjectType { struct GlobalState { bool done; + int32_t applying_all_count = 0; bool applying_all; // Selection std::string websocket_server_selection; diff --git a/src/master/main.cpp b/src/master/main.cpp index 0131bddd..b72055a0 100644 --- a/src/master/main.cpp +++ b/src/master/main.cpp @@ -118,7 +118,10 @@ void hwGetterFeedback(std::string ip, json hw){ } void applyAllFeedback(){ - global_state->applying_all = false; + global_state->applying_all_count++; + if(global_state->applying_all_count >= master->getServerCount()){ + global_state->applying_all = false; + } } void updateServerList(){ diff --git a/src/server/GoProController.h b/src/server/GoProController.h index 33017e60..e999c663 100644 --- a/src/server/GoProController.h +++ b/src/server/GoProController.h @@ -222,6 +222,7 @@ class GoProController { /// }] /// std::string setSettingAll(const std::string source, const std::string target, int32_t preset, json value); + void setSettingCancelAll(); #pragma endregion #pragma region Webcam part of calls @@ -410,6 +411,11 @@ class GoProController { private: #pragma region private variable + /// + /// State of current server + /// Is applying something + /// + bool applying_cancel = false; /// /// The handle for mdns service manager /// diff --git a/src/server/controller/query.cpp b/src/server/controller/query.cpp index 08dd9e4e..62c3e1ec 100644 --- a/src/server/controller/query.cpp +++ b/src/server/controller/query.cpp @@ -119,10 +119,12 @@ std::string GoProController::setSetting(std::string target, int32_t ID, std::str std::string GoProController::setSettingAll(const std::string source, const std::string target, int32_t preset, json value){ json arr = json::array(); json res = json::object(); + applying_cancel = false; std::string address = ""; if(target.size() > 0){ // Apply to single target std::vector results = _setSetting(target, preset, value); for(int32_t i = 0; i < results.size(); i++){ + if(applying_cancel) continue; address = results[i].first; bool vaild = json::accept(results[i].second); if(vaild){ @@ -147,6 +149,7 @@ std::string GoProController::setSettingAll(const std::string source, const std:: std::vector results = _setAllSetting(buffer, preset, value); std::cout << "[LOG] next step of setSettingAll" << std::endl; for(int32_t i = 0; i < results.size(); i++){ + if(applying_cancel) continue; address = results[i].first; bool vaild = json::accept(results[i].second); if(vaild){ @@ -165,3 +168,6 @@ std::string GoProController::setSettingAll(const std::string source, const std:: return arr.dump(); } +void GoProController::setSettingCancelAll() { + applying_cancel = true; +} \ No newline at end of file diff --git a/src/server/main.cpp b/src/server/main.cpp index 77d9987d..e68bc1e9 100644 --- a/src/server/main.cpp +++ b/src/server/main.cpp @@ -232,6 +232,9 @@ void QueryAction(const WebSocketChannelPtr& channel, json j){ r["data"] = json::array(); } channel->send(getPacket("query:set", r)); + } + else if(name == "setall_cancel"){ + } else if(name == "setall"){ resultText = controller.setSettingAll(source, target, preset, jvalue); From 7f000e9dc9fec8c1e4c8e3dd5fcd6d6efbb0daaa Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Mon, 4 May 2026 09:25:41 +0800 Subject: [PATCH 23/64] First commit --- src/master/windows/websocket_server.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/master/windows/websocket_server.cpp b/src/master/windows/websocket_server.cpp index 2680b469..19ccfd53 100644 --- a/src/master/windows/websocket_server.cpp +++ b/src/master/windows/websocket_server.cpp @@ -15,6 +15,7 @@ WebsocketWindow::WebsocketWindow( title = "Websocket Dashboard"; } + WebsocketWindow::~WebsocketWindow(){ } From 84ecfd8a6f40ed0e578d6f742658045ed60f0b0f Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Mon, 4 May 2026 10:13:35 +0800 Subject: [PATCH 24/64] Added media download name rule type --- src/common/camera_other.h | 17 +++++++++++++++-- src/master/windows/inspector.h | 7 +++++++ src/master/windows/inspector/inspector.cpp | 11 +++++++++++ src/master/windows/inspector/media.cpp | 22 ++++++++++++++++++++++ 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/src/common/camera_other.h b/src/common/camera_other.h index c16d125e..3233d0b0 100644 --- a/src/common/camera_other.h +++ b/src/common/camera_other.h @@ -3,9 +3,9 @@ #define CAMERA_OTHER #include +#pragma region GoPro Mode #define GOPRO_MODE_SIZE 9 #define GOPRO_MODE_NAME "Webcam Mode" - const static char* GOPRO_MODE_STRING[] = { "Video", "Photo Burst", @@ -17,7 +17,6 @@ const static char* GOPRO_MODE_STRING[] = { "Timelapse Video", "Timelapse Night Video", }; - const static int32_t GOPRO_MODE_VALUE[] = { 0, // Video 65538, // Photo Burst @@ -29,6 +28,20 @@ const static int32_t GOPRO_MODE_VALUE[] = { 131073, // Timelapse Video 131074, // Timelapse Night Video }; +#pragma endregion + +#pragma region Media Download Type +#define MEDIA_DOWNLOAD_TYPE_SIZE 3 +#define MEDIA_DOWNLOAD_TYPE_NAME "Media Download Type" +const static char* MEDIA_DOWNLOAD_TYPE_STRING[] = { + "All", + "Front Chars", + "Back Chars" +}; +const static int32_t MEDIA_DOWNLOAD_TYPE_VALUE[] = { + 0, 1, 2 +}; +#pragma endregion #define WEBCAM_START_RES_SIZE 3 #define WEBCAM_START_RES_NAME "Webcam Resolution" diff --git a/src/master/windows/inspector.h b/src/master/windows/inspector.h index 1107fd93..09c0cc2d 100644 --- a/src/master/windows/inspector.h +++ b/src/master/windows/inspector.h @@ -66,4 +66,11 @@ class InspectorWindow : public BaseWindow { bool put_finish; bool should_disabled; bool applying_all_last; + /// + /// 0: None + /// 1: Front Characters + /// 2: Back Characters + /// + int32_t media_name_rule_type; + int32_t media_name_character_count; }; diff --git a/src/master/windows/inspector/inspector.cpp b/src/master/windows/inspector/inspector.cpp index 8e82b2fb..95c85eb2 100644 --- a/src/master/windows/inspector/inspector.cpp +++ b/src/master/windows/inspector/inspector.cpp @@ -49,6 +49,8 @@ json InspectorWindow::get_window_data() { json data = json::object(); data["put_finish"] = put_finish; data["create_date_folder"] = create_date_folder; + data["media_name_rule_type"] = media_name_rule_type; + data["media_name_character_count"] = media_name_character_count; data["current_download_location"] = state->current_download_location; data["setting_order"] = json::object(); data["status_order"] = json::object(); @@ -74,6 +76,15 @@ void InspectorWindow::set_window_data(json data) { if(data["create_date_folder"].is_boolean()){ create_date_folder = data["create_date_folder"].get(); } + if(data["media_name_rule_type"].is_number()){ + media_name_rule_type = data["media_name_rule_type"].get(); + } + if(data["media_name_character_count"].is_number()){ + media_name_character_count = data["media_name_character_count"].get(); + } + if(data["put_finish"].is_number()){ + put_finish = data["put_finish"].get(); + } if(data["current_download_location"].is_string()){ state->current_download_location = data["current_download_location"].get(); } diff --git a/src/master/windows/inspector/media.cpp b/src/master/windows/inspector/media.cpp index a123c99f..a3e3a57a 100644 --- a/src/master/windows/inspector/media.cpp +++ b/src/master/windows/inspector/media.cpp @@ -94,6 +94,28 @@ void InspectorWindow::draw_media_global(){ state->update_server(); } + const char* selection = MEDIA_DOWNLOAD_TYPE_STRING[media_name_rule_type]; + if(ImGui::BeginCombo("Media Name Rule", selection)){ + for(int32_t i = 0; i < MEDIA_DOWNLOAD_TYPE_SIZE; i++){ + bool selected = (media_name_rule_type == i); + if(ImGui::Selectable(MEDIA_DOWNLOAD_TYPE_STRING[i], selected)){ + media_name_rule_type = i; + state->update_server(); + } + if(selected){ + ImGui::SetItemDefaultFocus(); + } + } + ImGui::EndCombo(); + } + + if(media_name_rule_type > 0){ + if(ImGui::InputInt("Character Count", &media_name_character_count, 1, 5)){ + if(media_name_character_count < 1) media_name_character_count = 1; + state->update_server(); + } + } + if(ImGui::IsItemHovered()) ImGui::SetTooltip("Open file explorer for path select directory"); if(camera_ip >= 0){ std::shared_ptr t = master->getCameras()[camera_ip]; From 32f33f41e65947da8e127ecc27971162b281e53e Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Mon, 4 May 2026 10:36:20 +0800 Subject: [PATCH 25/64] Update download media argument to a struct --- src/master/GoProMaster.cpp | 12 ++++++------ src/master/GoProMaster.h | 11 +++++++++-- src/master/windows/inspector/media.cpp | 12 ++++++++++-- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/master/GoProMaster.cpp b/src/master/GoProMaster.cpp index b2ea2a66..3fa4b578 100644 --- a/src/master/GoProMaster.cpp +++ b/src/master/GoProMaster.cpp @@ -280,9 +280,9 @@ void GoProMaster::media_only(const std::string command, std::string target){ } -void GoProMaster::download_last_media(const std::string dir, bool put_finish){ +void GoProMaster::download_last_media(const DownloadMediaParameters params){ std::thread([=](){ - if(put_finish){ + if(params.put_finish){ downloading_last_media_flag = 2; }else{ downloading_last_media_flag = 1; @@ -307,7 +307,7 @@ void GoProMaster::download_last_media(const std::string dir, bool put_finish){ data["value"]["item"] = s->name; data["value"]["ip"] = s->ip; data["value"]["local"] = islocal; - data["value"]["dir"] = dir; + data["value"]["dir"] = params.dir; data["value"]["filename"] = filename; for(auto ss : servers){ @@ -324,9 +324,9 @@ void GoProMaster::download_last_media(const std::string dir, bool put_finish){ }).detach(); } -void GoProMaster::download_last_media(const std::string ip, const std::string dir, bool put_finish){ +void GoProMaster::download_last_media(const std::string ip, const DownloadMediaParameters params){ std::thread([=](){ - if(put_finish){ + if(params.put_finish){ downloading_last_media_flag = 2; }else{ downloading_last_media_flag = 1; @@ -351,7 +351,7 @@ void GoProMaster::download_last_media(const std::string ip, const std::string di data["value"]["item"] = s->name; data["value"]["ip"] = s->ip; data["value"]["local"] = islocal; - data["value"]["dir"] = dir; + data["value"]["dir"] = params.dir; data["value"]["filename"] = filename; for(auto ss : servers){ diff --git a/src/master/GoProMaster.h b/src/master/GoProMaster.h index 9e5c932d..fe9b36ad 100644 --- a/src/master/GoProMaster.h +++ b/src/master/GoProMaster.h @@ -24,6 +24,13 @@ typedef void (*camera_log_feedback)(std::string key, std::string value); typedef void (*camera_preset_save)(); typedef void (*camera_apply_all_feedback)(); +struct DownloadMediaParameters { + std::string dir; + bool put_finish; + int32_t type; + int32_t c_count; +}; + /// /// GoPro Master Worker /// Use this hub stuff to control multiple websocket server or camera @@ -88,8 +95,8 @@ class GoProMaster { void preview_start(std::string server, std::string target); void preview_end(std::string server, std::string target); void media_only(const std::string command, std::string target = ""); - void download_last_media(const std::string dir, bool put_finish); - void download_last_media(const std::string ip, const std::string dir, bool put_finish); + void download_last_media(const DownloadMediaParameters params); + void download_last_media(const std::string ip, const DownloadMediaParameters params); void presetSwitch(const std::string server, const std::string target, int32_t mode); void locate(const std::string server, const std::string target); diff --git a/src/master/windows/inspector/media.cpp b/src/master/windows/inspector/media.cpp index a3e3a57a..fcf20cfa 100644 --- a/src/master/windows/inspector/media.cpp +++ b/src/master/windows/inspector/media.cpp @@ -38,6 +38,12 @@ void InspectorWindow::draw_media_global(){ ImVec2 button_size = ImVec2(size.x / 2.0F - style.ItemSpacing.x, 0); ImVec2 button3_size = ImVec2(size.x / 3.0F - style.ItemSpacing.x, 0); + DownloadMediaParameters params; + params.dir = state->current_download_location; + params.put_finish = put_finish; + params.type = media_name_rule_type; + params.c_count = media_name_character_count; + int32_t camera_ip = master->findCamera(state->current_camera_server, state->current_camera_item); if(ImGui::InputText("Media Download", &state->current_download_location)){ state->update_server(); @@ -53,7 +59,8 @@ void InspectorWindow::draw_media_global(){ buffer.append("/" + date); } fs::create_directories(buffer); - master->download_last_media(buffer, put_finish); + params.dir = buffer; + master->download_last_media(params); } } if(ImGui::IsItemHovered()) ImGui::SetTooltip("Download all exist camera instances"); @@ -69,7 +76,8 @@ void InspectorWindow::draw_media_global(){ buffer.append("/" + date); } fs::create_directories(buffer); - master->download_last_media(state->current_camera_item, buffer, put_finish); + params.dir = buffer; + master->download_last_media(state->current_camera_item, params); } } if(ImGui::IsItemHovered()) ImGui::SetTooltip("Download current select camera instance"); From bb0ac518ef3f125e7fa3435cd9b5e1bd3a04d6a8 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Mon, 4 May 2026 13:38:20 +0800 Subject: [PATCH 26/64] Update filename updater --- src/master/GoProMaster.cpp | 59 +++++++------------------- src/master/GoProMaster.h | 1 - src/master/windows/inspector/media.cpp | 2 +- 3 files changed, 16 insertions(+), 46 deletions(-) diff --git a/src/master/GoProMaster.cpp b/src/master/GoProMaster.cpp index 3fa4b578..96e82ad8 100644 --- a/src/master/GoProMaster.cpp +++ b/src/master/GoProMaster.cpp @@ -280,7 +280,7 @@ void GoProMaster::media_only(const std::string command, std::string target){ } -void GoProMaster::download_last_media(const DownloadMediaParameters params){ +void GoProMaster::download_last_media(const std::string ip, const DownloadMediaParameters params){ std::thread([=](){ if(params.put_finish){ downloading_last_media_flag = 2; @@ -292,55 +292,26 @@ void GoProMaster::download_last_media(const DownloadMediaParameters params){ for(auto& s : cameras){ if(!s->connected) continue; - + if(ip.size() > 0 && s->ip != ip) continue; std::string filename = s->name + fs::path(s->last_media).extension().string(); if(filename.size() == 0 || s->name.size() == 0) { std::cerr << "[download_last_media] filename size is 0, we just skip..." << std::endl; continue; } - bool islocal = s->server == "127.0.0.1"; - - json data = json::object(); - data["key"] = "media"; - data["value"] = json::object(); - data["value"]["name"] = "url"; - data["value"]["item"] = s->name; - data["value"]["ip"] = s->ip; - data["value"]["local"] = islocal; - data["value"]["dir"] = params.dir; - data["value"]["filename"] = filename; - - for(auto ss : servers){ - if(s->server == ss->ip && ss->connected){ - ss->client.send(data.dump()); - downloading_last_media_total++; - break; + size_t filename_size = filename.size(); + if(params.c_count > 0){ + std::string ccc = ""; + if(params.type == 1){ + filename.reserve(); } - } - } - if(downloading_last_media_total == 0){ - downloading_last_media_flag = 0; - } - }).detach(); -} - -void GoProMaster::download_last_media(const std::string ip, const DownloadMediaParameters params){ - std::thread([=](){ - if(params.put_finish){ - downloading_last_media_flag = 2; - }else{ - downloading_last_media_flag = 1; - } - downloading_last_media_total = 0; - downloading_last_media_done = 0; - - for(auto& s : cameras){ - if(!s->connected) continue; - if(s->ip != ip) continue; - std::string filename = s->name + fs::path(s->last_media).extension().string(); - if(filename.size() == 0 || s->name.size() == 0) { - std::cerr << "[download_last_media] filename size is 0, we just skip..." << std::endl; - continue; + for(int32_t i = 0; i < params.c_count && i < filename_size; i++){ + ccc += filename.at(filename.size() - 1); + filename.pop_back(); + } + if(params.type == 2){ + ccc.reserve(); + } + filename = ccc; } bool islocal = s->server == "127.0.0.1"; diff --git a/src/master/GoProMaster.h b/src/master/GoProMaster.h index fe9b36ad..12009739 100644 --- a/src/master/GoProMaster.h +++ b/src/master/GoProMaster.h @@ -95,7 +95,6 @@ class GoProMaster { void preview_start(std::string server, std::string target); void preview_end(std::string server, std::string target); void media_only(const std::string command, std::string target = ""); - void download_last_media(const DownloadMediaParameters params); void download_last_media(const std::string ip, const DownloadMediaParameters params); void presetSwitch(const std::string server, const std::string target, int32_t mode); diff --git a/src/master/windows/inspector/media.cpp b/src/master/windows/inspector/media.cpp index fcf20cfa..34395198 100644 --- a/src/master/windows/inspector/media.cpp +++ b/src/master/windows/inspector/media.cpp @@ -60,7 +60,7 @@ void InspectorWindow::draw_media_global(){ } fs::create_directories(buffer); params.dir = buffer; - master->download_last_media(params); + master->download_last_media("", params); } } if(ImGui::IsItemHovered()) ImGui::SetTooltip("Download all exist camera instances"); From 04a8d3bc31cebfe8687c5cbbd3778fda349e929a Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Mon, 4 May 2026 13:51:39 +0800 Subject: [PATCH 27/64] Added denoise option --- src/common/camera_code.h | 6 ++++++ src/common/camera_setting.h | 10 +++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/common/camera_code.h b/src/common/camera_code.h index 488f9cc7..34398037 100644 --- a/src/common/camera_code.h +++ b/src/common/camera_code.h @@ -322,6 +322,7 @@ const static int32_t GOPRO_MEDIA_STATUS_IDS[] = { // Lookup functions inline const int32_t GET_SETTING_SIZE_BY_ID(int32_t x) { switch(x) { + case DENOISE_ID : return DENOISE_SIZE; case BURST_OUTPUT_ID : return BURST_OUTPUT_SIZE; case PHOTO_BURST_RATE_ID : return PHOTO_BURST_RATE_SIZE; case ISO_MIN_BURST_ID : return ISO_MIN_BURST_SIZE; @@ -393,6 +394,7 @@ inline const int32_t GET_SETTING_SIZE_BY_ID(int32_t x) { inline const int32_t GET_SETTING_AVA_BY_ID(int32_t x) { switch(x) { + case DENOISE_ID : return DENOISE_AVA; case BURST_OUTPUT_ID : return BURST_OUTPUT_AVA; case PHOTO_BURST_RATE_ID : return PHOTO_BURST_RATE_AVA; case ISO_MIN_BURST_ID : return ISO_MIN_BURST_AVA; @@ -464,6 +466,7 @@ inline const int32_t GET_SETTING_AVA_BY_ID(int32_t x) { inline const char* GET_SETTING_NAME_BY_ID(int32_t x) { switch(x) { + case DENOISE_ID : return DENOISE_NAME; case BURST_OUTPUT_ID : return BURST_OUTPUT_NAME; case PHOTO_BURST_RATE_ID : return PHOTO_BURST_RATE_NAME; case ISO_MIN_BURST_ID : return ISO_MIN_BURST_NAME; @@ -535,6 +538,7 @@ inline const char* GET_SETTING_NAME_BY_ID(int32_t x) { inline const char** GET_SETTING_STRING_BY_ID(int32_t x) { switch(x) { + case DENOISE_ID : return DENOISE_STRING; case BURST_OUTPUT_ID : return BURST_OUTPUT_STRING; case PHOTO_BURST_RATE_ID : return PHOTO_BURST_RATE_STRING; case ISO_MIN_BURST_ID : return ISO_MIN_BURST_STRING; @@ -606,6 +610,7 @@ inline const char** GET_SETTING_STRING_BY_ID(int32_t x) { inline const int32_t* GET_SETTING_VALUE_BY_ID(int32_t x) { switch(x) { + case DENOISE_ID : return DENOISE_VALUE; case BURST_OUTPUT_ID : return BURST_OUTPUT_VALUE; case PHOTO_BURST_RATE_ID : return PHOTO_BURST_RATE_VALUE; case ISO_MIN_BURST_ID : return ISO_MIN_BURST_VALUE; @@ -677,6 +682,7 @@ inline const int32_t* GET_SETTING_VALUE_BY_ID(int32_t x) { inline const int32_t* GET_SETTING_SUPPORT_BY_ID(int32_t x) { switch(x) { + case DENOISE_ID : return DENOISE_SUPPORT; case BURST_OUTPUT_ID : return BURST_OUTPUT_SUPPORT; case PHOTO_BURST_RATE_ID : return PHOTO_BURST_RATE_SUPPORT; case ISO_MIN_BURST_ID : return ISO_MIN_BURST_SUPPORT; diff --git a/src/common/camera_setting.h b/src/common/camera_setting.h index 23e9873f..6f4bd561 100644 --- a/src/common/camera_setting.h +++ b/src/common/camera_setting.h @@ -2172,7 +2172,7 @@ const static int32_t SHARPNESS_SUPPORT[] = { #define DENOISE_ID 198 #define DENOISE_SIZE 3 #define DENOISE_NAME "Denoise" -#define DENOISE_AVA MODEL_MAX2_ALL +#define DENOISE_AVA MODEL_MAX2&MODEL_13 const static char* DENOISE_STRING[] = { "High", "Midium", @@ -2181,12 +2181,12 @@ const static char* DENOISE_STRING[] = { const static int32_t DENOISE_VALUE[] = { 2, // High 1, // Midium - 1, // Low + 0, // Low }; const static int32_t DENOISE_SUPPORT[] = { - MODEL_MAX2_ALL, // High - MODEL_MAX2_ALL, // Midium - MODEL_MAX2_ALL, // Low + MODEL_MAX2&MODEL_13, // High + MODEL_MAX2&MODEL_13, // Midium + MODEL_MAX2&MODEL_13, // Low }; #pragma endregio From 2afcf199e0928e1046813e8ab81a4adf257ab983 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Mon, 4 May 2026 13:58:01 +0800 Subject: [PATCH 28/64] Added denoise option for model 13 --- src/common/camera_setting.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/common/camera_setting.h b/src/common/camera_setting.h index 6f4bd561..cc5cc5e7 100644 --- a/src/common/camera_setting.h +++ b/src/common/camera_setting.h @@ -2172,11 +2172,11 @@ const static int32_t SHARPNESS_SUPPORT[] = { #define DENOISE_ID 198 #define DENOISE_SIZE 3 #define DENOISE_NAME "Denoise" -#define DENOISE_AVA MODEL_MAX2&MODEL_13 +#define DENOISE_AVA MODEL_MAX2|MODEL_13 const static char* DENOISE_STRING[] = { "High", "Midium", - "Low" + "Low", }; const static int32_t DENOISE_VALUE[] = { 2, // High @@ -2184,9 +2184,9 @@ const static int32_t DENOISE_VALUE[] = { 0, // Low }; const static int32_t DENOISE_SUPPORT[] = { - MODEL_MAX2&MODEL_13, // High - MODEL_MAX2&MODEL_13, // Midium - MODEL_MAX2&MODEL_13, // Low + MODEL_MAX2|MODEL_13, // High + MODEL_MAX2|MODEL_13, // Midium + MODEL_MAX2|MODEL_13, // Low }; #pragma endregio From d0560a5c5a3aaf62b937fbf19642d234b30f31ec Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Mon, 4 May 2026 16:29:56 +0800 Subject: [PATCH 29/64] First Commit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ac4f6417..21b18b12 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # GoPro Controller Tool for control multiple GoPro Cameras, The design is for above 100 cameras connection. - + [Documentation](https://github.com/Elly2018/GoPro_Controller/wiki) ## Application Requirement From 9d6173a87e0775259b5f0a412a057436af8e3c22 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Tue, 5 May 2026 10:35:02 +0800 Subject: [PATCH 30/64] Fixed clone --- src/master/GoProMaster.cpp | 105 ++++++++++++++++++------ src/master/GoProMaster.h | 4 + src/master/data/server_connection.h | 2 +- src/master/windows/websocket_server.cpp | 8 +- 4 files changed, 88 insertions(+), 31 deletions(-) diff --git a/src/master/GoProMaster.cpp b/src/master/GoProMaster.cpp index 96e82ad8..0f2df647 100644 --- a/src/master/GoProMaster.cpp +++ b/src/master/GoProMaster.cpp @@ -25,7 +25,7 @@ GoProMaster::~GoProMaster() { t1.join(); } for (auto& s : servers) { - s->client.close(); + s->client->close(); std::lock_guard lock(camera_mtx); cleanCameraFromServer(s->ip); } @@ -40,9 +40,10 @@ std::string GoProMaster::addServer(const std::string& ip) { } auto conn = std::make_shared(); + conn->client = std::make_shared(); conn->ip = ip; - conn->client.onopen = [conn, this]() { + conn->client->onopen = [conn, this]() { std::cout << "Connected to server: " << conn->ip << std::endl; conn->connected = true; { @@ -52,12 +53,12 @@ std::string GoProMaster::addServer(const std::string& ip) { ImGui::InsertNotification(toast); } }; - conn->client.onmessage = [conn, this](const std::string& msg) { + conn->client->onmessage = [conn, this](const std::string& msg) { std::thread([=]() { processMessage(conn->ip, msg); }).detach(); }; - conn->client.onclose = [conn, this]() { + conn->client->onclose = [conn, this]() { if(conn->connected){ std::cout << "Disconnected from server: " << conn->ip << std::endl; conn->connected = false; @@ -85,7 +86,7 @@ void GoProMaster::reconnectAll() { std::cout << "Connecting to " << s->ip << "..." << std::endl; // Assuming ws://ip:9090 based on server implementation std::string url = "ws://" + s->ip + ":9090"; - s->client.open(url.c_str()); + s->client->open(url.c_str()); } } } @@ -94,7 +95,7 @@ void GoProMaster::disconnectAll(){ for (auto& s : servers) { if (s->connected) { std::cout << "Disconnect to " << s->ip << "..." << std::endl; - s->client.close(); + s->client->close(); } } } @@ -114,7 +115,7 @@ void GoProMaster::reconnect(const std::string& ip){ if(s->ip == ip && !s->connected){ std::cout << "Connecting to " << s->ip << "..." << std::endl; std::string url = "ws://" + s->ip + ":9090"; - s->client.open(url.c_str()); + s->client->open(url.c_str()); break; } } @@ -124,7 +125,7 @@ void GoProMaster::disconnect(const std::string& ip){ for(auto& s : servers){ if(s->ip == ip && s->connected){ std::cout << "Disconnecting to " << s->ip << "..." << std::endl; - s->client.close(); + s->client->close(); break; } } @@ -149,7 +150,7 @@ void GoProMaster::command_only(const std::string command, std::string target){ for(auto s : servers){ if(s->connected){ - s->client.send(data.dump()); + s->client->send(data.dump()); } } } @@ -163,7 +164,7 @@ void GoProMaster::command_only(const std::string server, const std::string comma for(auto s : servers){ if(s->ip == server && s->connected){ - s->client.send(data.dump()); + s->client->send(data.dump()); break; } } @@ -179,7 +180,7 @@ void GoProMaster::command_with_value(const std::string command, std::string targ for(auto s : servers){ if(s->connected){ - s->client.send(data.dump()); + s->client->send(data.dump()); } } } @@ -193,7 +194,7 @@ void GoProMaster::query_only(const std::string command, std::string target){ for(auto s : servers){ if(s->connected){ - s->client.send(data.dump()); + s->client->send(data.dump()); } } } @@ -207,7 +208,7 @@ void GoProMaster::query_only(const std::string server, const std::string command for(auto s : servers){ if(s->ip == server && s->connected){ - s->client.send(data.dump()); + s->client->send(data.dump()); break; } } @@ -222,7 +223,7 @@ void GoProMaster::webcam_only(const std::string command, std::string target){ for(auto s : servers){ if(s->connected){ - s->client.send(data.dump()); + s->client->send(data.dump()); } } } @@ -236,7 +237,7 @@ void GoProMaster::webcam_only(const std::string server, const std::string comman for(auto s : servers){ if(s->ip == server && s->connected){ - s->client.send(data.dump()); + s->client->send(data.dump()); break; } } @@ -255,7 +256,7 @@ void GoProMaster::preview_start(std::string server, std::string target){ for(auto s : servers){ if(s->ip == server && s->connected){ - s->client.send(data.dump()); + s->client->send(data.dump()); break; } } @@ -270,7 +271,7 @@ void GoProMaster::preview_end(std::string server, std::string target){ for(auto s : servers){ if((s->ip == server || server.size() == 0) && s->connected){ - s->client.send(data.dump()); + s->client->send(data.dump()); break; } } @@ -327,7 +328,7 @@ void GoProMaster::download_last_media(const std::string ip, const DownloadMediaP for(auto ss : servers){ if(s->server == ss->ip && ss->connected){ - ss->client.send(data.dump()); + ss->client->send(data.dump()); downloading_last_media_total++; break; } @@ -350,7 +351,7 @@ void GoProMaster::presetSwitch(const std::string server, const std::string targe get_status["value"]["name"] = "load"; get_status["value"]["mode"] = mode; get_status["value"]["target"] = target; - s->client.send(get_status.dump()); + s->client->send(get_status.dump()); } }).detach(); } @@ -384,7 +385,7 @@ void GoProMaster::apply(const std::string& ip, const std::string& target, const get_status["value"]["target"] = target; get_status["value"]["id"] = id; get_status["value"]["value"] = std::to_string(value); - s->client.send(get_status.dump()); + s->client->send(get_status.dump()); } }).detach(); } @@ -399,7 +400,7 @@ void GoProMaster::applyAll(const std::string& ip, const json& res){ get_status["value"]["source"] = ip; get_status["value"]["name"] = "setall"; get_status["value"]["value"] = res; - s->client.send(get_status.dump()); + s->client->send(get_status.dump()); } }).detach(); } @@ -507,6 +508,7 @@ bool GoProMaster::remove_preset(const std::string name){ } return false; } + std::vector GoProMaster::get_preset_names(){ if(!(*preset_ptr)["data"].is_array()) { (*preset_ptr)["data"] = json::array(); @@ -531,16 +533,67 @@ const std::vector GoProMaster::getCameras_Clone() { { std::lock_guard lock(camera_mtx); for(auto& i : getCameras()){ - buffer.push_back(*i.get()); + CameraInfo sc = CameraInfo(); + sc.hw = i->hw; + sc.ip = i->ip; + sc.last_media = i->last_media; + sc.name = i->name; + sc.serial = i->serial; + sc.connected = i->connected; + sc.state = i->state; + sc.server = i->server; + buffer.push_back(sc); } } return buffer; } +const CameraInfo GoProMaster::getCamera_Clone(int32_t index) { + if(index < 0 || index >= cameras.size()) return CameraInfo(); + CameraInfo sc = CameraInfo(); + auto i = getCameras().at(index).get(); + sc.hw = i->hw; + sc.ip = i->ip; + sc.last_media = i->last_media; + sc.name = i->name; + sc.serial = i->serial; + sc.connected = i->connected; + sc.state = i->state; + sc.server = i->server; + return sc; +} + const std::vector>& GoProMaster::getServers() const { return servers; } +const std::vector GoProMaster::getServers_Clone() { + std::vector buffer = std::vector(); + { + std::lock_guard lock(server_mtx); + for(auto& i : getServers()){ + ServerConnection sc = ServerConnection(); + sc.ip = i->ip; + sc.connected = i->connected; + sc.last_message = i->last_message; + sc.client = i->client; + buffer.push_back(sc); + } + } + return buffer; +} + +const ServerConnection GoProMaster::getServer_Clone(int32_t index) { + if(index < 0 || index >= servers.size()) return ServerConnection(); + ServerConnection sc = ServerConnection(); + auto i = getServers().at(index).get(); + sc.ip = i->ip; + sc.connected = i->connected; + sc.last_message = i->last_message; + sc.client = i->client; + return sc; +} + void GoProMaster::update(){ while (!done) { for (auto& s : servers) { @@ -551,7 +604,7 @@ void GoProMaster::update(){ get_status["value"] = json::object(); get_status["value"]["name"] = "ip"; ipQueryFinish.insert_or_assign(s->ip, true); - s->client.send(get_status.dump()); + s->client->send(get_status.dump()); } for (auto& s : servers) { @@ -562,7 +615,7 @@ void GoProMaster::update(){ get_status["value"] = json::object(); get_status["value"]["name"] = "getall"; stateQueryFinish.insert_or_assign(s->ip, true); - s->client.send(get_status.dump()); + s->client->send(get_status.dump()); } for (auto& s : servers) { @@ -573,7 +626,7 @@ void GoProMaster::update(){ get_status["value"] = json::object(); get_status["value"]["name"] = "lastmedia"; mediaQueryFinish.insert_or_assign(s->ip, true); - s->client.send(get_status.dump()); + s->client->send(get_status.dump()); } std::lock_guard lock(locate_mtx); @@ -849,7 +902,7 @@ void GoProMaster::processMessage(const std::string& server, const std::string& m void GoProMaster::sendToAll(const std::string& msg) { for (auto& s : servers) { if (s->connected) { - s->client.send(msg); + s->client->send(msg); } } } diff --git a/src/master/GoProMaster.h b/src/master/GoProMaster.h index 12009739..606f2311 100644 --- a/src/master/GoProMaster.h +++ b/src/master/GoProMaster.h @@ -132,6 +132,7 @@ class GoProMaster { */ std::mutex camera_mtx; std::mutex locate_mtx; + std::mutex server_mtx; // ---------------------------------------------------------- // @@ -146,10 +147,13 @@ class GoProMaster { * Get current camera record (Clone, For thread optimization) */ const std::vector getCameras_Clone(); + const CameraInfo getCamera_Clone(int32_t index); /** * Get current websocket server record */ const std::vector>& getServers() const; + const std::vector getServers_Clone(); + const ServerConnection getServer_Clone(int32_t index); private: /** * All cameras record for master diff --git a/src/master/data/server_connection.h b/src/master/data/server_connection.h index 997d35e9..ad423e97 100644 --- a/src/master/data/server_connection.h +++ b/src/master/data/server_connection.h @@ -19,7 +19,7 @@ struct ServerConnection { /** * The libhv websocket client */ - hv::WebSocketClient client; + std::shared_ptr client; /** * Current connection state */ diff --git a/src/master/windows/websocket_server.cpp b/src/master/windows/websocket_server.cpp index 19ccfd53..bd1af7d4 100644 --- a/src/master/windows/websocket_server.cpp +++ b/src/master/windows/websocket_server.cpp @@ -86,17 +86,17 @@ void WebsocketWindow::render(){ ImGui::TableSetupColumn("Last Message"); ImGui::TableHeadersRow(); - for (const auto& s : master->getServers()) { + for (const auto& s : master->getServers_Clone()) { ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); - ImGui::Text("%s", s->ip.c_str()); + ImGui::Text("%s", s.ip.c_str()); ImGui::TableSetColumnIndex(1); - if (s->connected) + if (s.connected) ImGui::TextColored(ImVec4(0,1,0,1), "Connected"); else ImGui::TextColored(ImVec4(1,0,0,1), "Disconnected"); ImGui::TableSetColumnIndex(2); - ImGui::Text("%s", s->last_message.c_str()); + ImGui::Text("%s", s.last_message.c_str()); } ImGui::EndTable(); } From 66d880775e231990dab325df71d229d08e359c92 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Tue, 5 May 2026 11:28:16 +0800 Subject: [PATCH 31/64] Fixed camera list, let it using copy, prevent lock --- src/master/GoProMaster.cpp | 16 +- src/master/GoProMaster.h | 1 + src/master/data/camera_info.h | 4 +- src/master/windows/camera_list.h | 12 +- .../windows/camera_list/camera_list.cpp | 77 +- .../windows/camera_list/display_header.cpp | 44 +- .../windows/camera_list/display_state.cpp | 772 +++++++++--------- 7 files changed, 466 insertions(+), 460 deletions(-) diff --git a/src/master/GoProMaster.cpp b/src/master/GoProMaster.cpp index 0f2df647..686f7059 100644 --- a/src/master/GoProMaster.cpp +++ b/src/master/GoProMaster.cpp @@ -534,13 +534,13 @@ const std::vector GoProMaster::getCameras_Clone() { std::lock_guard lock(camera_mtx); for(auto& i : getCameras()){ CameraInfo sc = CameraInfo(); - sc.hw = i->hw; + sc.hw = json::parse(i->hw.dump()); + sc.state = json::parse(i->state.dump()); sc.ip = i->ip; sc.last_media = i->last_media; sc.name = i->name; sc.serial = i->serial; sc.connected = i->connected; - sc.state = i->state; sc.server = i->server; buffer.push_back(sc); } @@ -1015,9 +1015,13 @@ bool GoProMaster::getStatusFromCamera(CameraInfo target, json& res){ } std::string GoProMaster::getBarInfo(const std::shared_ptr &c){ - json obj = c->state; + return getBarInfo(*c); +} + +std::string GoProMaster::getBarInfo(const CameraInfo &c){ + json obj = c.state; bool find = false; - std::string result = c->name + " " + c->serial + " " + c->ip + " "; + std::string result = c.name + " " + c.serial + " " + c.ip + " "; if(obj["settings"].is_object()){ if(obj["settings"]["2"].is_number()){ int32_t vr = obj["settings"]["2"].get(); @@ -1042,7 +1046,7 @@ std::string GoProMaster::getBarInfo(const std::shared_ptr &c){ find = true; } } - if(!find) return c->ip + " ..."; + if(!find) return c.ip + " ..."; return result; } @@ -1070,4 +1074,4 @@ int32_t GoProMaster::findCamera(const std::string server, const std::string ip){ ++index; } return -1; -} \ No newline at end of file +} diff --git a/src/master/GoProMaster.h b/src/master/GoProMaster.h index 606f2311..9893f626 100644 --- a/src/master/GoProMaster.h +++ b/src/master/GoProMaster.h @@ -229,6 +229,7 @@ class GoProMaster { bool getSettingsFromCamera(CameraInfo target, json& res); bool getStatusFromCamera(CameraInfo target, json& res); std::string getBarInfo(const std::shared_ptr &c); + std::string getBarInfo(const CameraInfo &c); size_t getServerCount(); int32_t findServer(const std::string ip); diff --git a/src/master/data/camera_info.h b/src/master/data/camera_info.h index 558ae38f..abf12384 100644 --- a/src/master/data/camera_info.h +++ b/src/master/data/camera_info.h @@ -29,6 +29,6 @@ struct CameraInfo { /** * The json states */ - json state; - json hw; + json state = json::object(); + json hw = json::object(); }; \ No newline at end of file diff --git a/src/master/windows/camera_list.h b/src/master/windows/camera_list.h index 591df14a..b2fe580e 100644 --- a/src/master/windows/camera_list.h +++ b/src/master/windows/camera_list.h @@ -45,15 +45,15 @@ class CameraListWindow : public BaseWindow { void set_window_data(json data) override; virtual void render() override; - virtual void draw_line(const std::shared_ptr& c); - virtual void draw_group_state(const std::shared_ptr& c); - virtual void draw_group_header(const std::shared_ptr& c); - virtual void item_event(const std::shared_ptr& c); - void onClick(const std::shared_ptr& c); + virtual void draw_line(const CameraInfo& c); + virtual void draw_group_state(const CameraInfo& c); + virtual void draw_group_header(const CameraInfo& c); + virtual void item_event(const CameraInfo& c); + void onClick(const CameraInfo& c); private: ImVec2 get_rect_size(); - std::vector> get_filtering_result(); + std::vector get_filtering_result(); std::string get_filter_string(FilterType type); std::string get_sort_string(SortType type); std::string toTimeCode(int32_t timer); diff --git a/src/master/windows/camera_list/camera_list.cpp b/src/master/windows/camera_list/camera_list.cpp index a13cc159..7b502ac9 100644 --- a/src/master/windows/camera_list/camera_list.cpp +++ b/src/master/windows/camera_list/camera_list.cpp @@ -60,7 +60,6 @@ void CameraListWindow::render(){ ImGui::Begin(title.c_str(), &enable, w_flag); { ImVec2 window_size = ImGui::GetWindowSize(); - std::lock_guard lock(master->camera_mtx); changed = ImGui::SliderInt("Item Size##Camera_List_Size", &size, 0, 15); changed = changed || ImGui::InputText("Search", &search); @@ -110,10 +109,10 @@ void CameraListWindow::render(){ float width = ImGui::GetWindowSize().x; // Total space size int32_t limit = static_cast((width / rect_size.x) - 0.5f); int32_t counter = 0; - std::vector> ciss = get_filtering_result(); + std::vector ciss = get_filtering_result(); ImGui::Text("Cal: %f/%f, Total: %d, Line: %d", width, rect_size.x, size, limit); for(const auto& c : ciss){ - if(c){ + if(c.ip.size() > 0){ try{ if(size == 0) draw_line(c); else { @@ -141,10 +140,10 @@ void CameraListWindow::render(){ } } -void CameraListWindow::draw_line(const std::shared_ptr& c){ - bool selected = c->ip == state->current_camera_item && c->server == state->current_camera_server; +void CameraListWindow::draw_line(const CameraInfo& c){ + bool selected = c.ip == state->current_camera_item && c.server == state->current_camera_server; std::string plusStatus = master->getBarInfo(c); - std::string plusID = plusStatus + "##CameraList_" + c->ip; + std::string plusID = plusStatus + "##CameraList_" + c.ip; if(ImGui::Selectable(plusID.c_str(), selected)){ // User select interaction onClick(c); @@ -152,60 +151,60 @@ void CameraListWindow::draw_line(const std::shared_ptr& c){ item_event(c); } -void CameraListWindow::item_event(const std::shared_ptr& c){ +void CameraListWindow::item_event(const CameraInfo& c){ if(ImGui::IsItemClicked(ImGuiMouseButton_Left) && ImGui::IsItemHovered()){ onClick(c); } if(ImGui::IsItemClicked(ImGuiMouseButton_Right) && ImGui::IsItemHovered()){ ImGui::OpenPopupOnItemClick(); } - if(ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left) && ImGui::IsItemHovered() && c->connected){ - master->preview_start(c->server, c->ip); - state->preview_ip = c->ip; - state->preview_server = c->server; + if(ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left) && ImGui::IsItemHovered() && c.connected){ + master->preview_start(c.server, c.ip); + state->preview_ip = c.ip; + state->preview_server = c.server; state->command_sender("preview_start"); } - if(ImGui::BeginPopupContextItem((title + "##Popup_Menu" + c->ip).c_str())){ - ImGui::BeginDisabled(!c->connected); + if(ImGui::BeginPopupContextItem((title + "##Popup_Menu" + c.ip).c_str())){ + ImGui::BeginDisabled(!c.connected); if (ImGui::Selectable("Connect")){ - master->command_only(c->server, "usb_on", c->ip); + master->command_only(c.server, "usb_on", c.ip); } if (ImGui::Selectable("Disconnect")){ - master->command_only(c->server, "usb_off", c->ip); + master->command_only(c.server, "usb_off", c.ip); } ImGui::Separator(); if (ImGui::Selectable("Reboot")) { - master->command_only(c->server, "reboot", c->ip); + master->command_only(c.server, "reboot", c.ip); } if (ImGui::Selectable("Shutdown")) { - master->command_only(c->server, "shutdown", c->ip); + master->command_only(c.server, "shutdown", c.ip); } if (ImGui::Selectable("Preview")) { - master->preview_start(c->server, c->ip); - state->preview_ip = c->ip; - state->preview_server = c->server; + master->preview_start(c.server, c.ip); + state->preview_ip = c.ip; + state->preview_server = c.server; state->command_sender("preview_start"); } ImGui::EndDisabled(); if (ImGui::Selectable("Delete")) { - master->command_only(c->server, "delete", c->ip); + master->command_only(c.server, "delete", c.ip); } ImGui::EndPopup(); } } -void CameraListWindow::onClick(const std::shared_ptr& c){ +void CameraListWindow::onClick(const CameraInfo& c){ state->current_setting_items_bind = false; - state->current_camera_item = c->ip; - state->current_camera_server = c->server; - state->current_camera_name = c->name; - std::cout << "Select camera: " << c->server << " " << c->ip << std::endl; - master->query_only(c->server, "get", c->ip); + state->current_camera_item = c.ip; + state->current_camera_server = c.server; + state->current_camera_name = c.name; + std::cout << "Select camera: " << c.server << " " << c.ip << std::endl; + master->query_only(c.server, "get", c.ip); //current_setting_items_bind = master.getSettingsFromCamera(*c, current_setting_items); } @@ -213,24 +212,24 @@ ImVec2 CameraListWindow::get_rect_size(){ return ImVec2(10 * (size + 10) + 20, 10 * (size + 10) + 20); } -std::vector> CameraListWindow::get_filtering_result(){ - auto buffer = master->getCameras(); - auto filtered = std::vector>(); +std::vector CameraListWindow::get_filtering_result(){ + auto buffer = master->getCameras_Clone(); + auto filtered = std::vector(); for(auto& c : buffer){ if(search.size() > 0){ - bool ip_contain = c->ip.find(search) != std::string::npos; - bool name_contain = c->name.find(search) != std::string::npos; - bool serial_contain = c->serial.find(search) != std::string::npos; + bool ip_contain = c.ip.find(search) != std::string::npos; + bool name_contain = c.name.find(search) != std::string::npos; + bool serial_contain = c.serial.find(search) != std::string::npos; if(!ip_contain && !name_contain && !serial_contain) continue; } if(filter == FilterType::Connect){ - if(c->connected == filter_connect){ + if(c.connected == filter_connect){ filtered.push_back(c); } }else if(filter == FilterType::Server){ - if(c->server == filter_ip){ + if(c.server == filter_ip){ filtered.push_back(c); } }else { @@ -239,12 +238,12 @@ std::vector> CameraListWindow::get_filtering_result( } if (sort == SortType::Name){ - std::sort(filtered.begin(), filtered.end(), [](const std::shared_ptr& a, const std::shared_ptr& b){ - return a->name < b->name; + std::sort(filtered.begin(), filtered.end(), [](const CameraInfo& a, const CameraInfo& b){ + return a.name < b.name; }); }else if (sort == SortType::IP){ - std::sort(filtered.begin(), filtered.end(), [](const std::shared_ptr& a, const std::shared_ptr& b){ - return a->ip < b->ip; + std::sort(filtered.begin(), filtered.end(), [](const CameraInfo& a, const CameraInfo& b){ + return a.ip < b.ip; }); } diff --git a/src/master/windows/camera_list/display_header.cpp b/src/master/windows/camera_list/display_header.cpp index 9f2c0d00..e32d96e3 100644 --- a/src/master/windows/camera_list/display_header.cpp +++ b/src/master/windows/camera_list/display_header.cpp @@ -1,17 +1,17 @@ #include "../camera_list.h" -void CameraListWindow::draw_group_header(const std::shared_ptr& c){ +void CameraListWindow::draw_group_header(const CameraInfo& c){ json status = json::object(); json setting = json::object(); int preset = 0; - master->getStatusFromCamera(*c, status); - master->getSettingsFromCamera(*c, setting); + master->getStatusFromCamera(c, status); + master->getSettingsFromCamera(c, setting); ImGui::BeginGroup(); ImGuiStyle& style = ImGui::GetStyle(); float fontsize = ImGui::GetFontSize(); - std::string id = c->ip + "##Grid_Item_ID"; - std::string pid = c->ip + "##Grid_Popup_Item_ID"; + std::string id = c.ip + "##Grid_Item_ID"; + std::string pid = c.ip + "##Grid_Popup_Item_ID"; ImGui::PushID(id.c_str()); ImDrawList* draw_list = ImGui::GetWindowDrawList(); @@ -37,11 +37,11 @@ void CameraListWindow::draw_group_header(const std::shared_ptr& c){ // Drawing outline { uint32_t col = col_red; - if(c->connected) col = col_greed; + if(c.connected) col = col_greed; draw_list->AddRect(image_pos + ImVec2(5, 5), image_pos_max - ImVec2(5, 5), col, 2.0F, 0, 2.0F); } // Drawing Battery - if(c->connected){ + if(c.connected){ bool batteryHave = false; bool batteryCharging = false; int precentage = 0; @@ -108,7 +108,7 @@ void CameraListWindow::draw_group_header(const std::shared_ptr& c){ } } // Drawing SD card - if(c->connected){ + if(c.connected){ bool sdHave = false; int64_t remaining = 0; uint32_t col_inner_color; @@ -157,7 +157,7 @@ void CameraListWindow::draw_group_header(const std::shared_ptr& c){ // Center text { std::string shutter_speed; - std::string camera_title = c->name; + std::string camera_title = c.name; std::string iso_setting; std::string white_balance_setting; float spacing = 0.75F; @@ -174,7 +174,7 @@ void CameraListWindow::draw_group_header(const std::shared_ptr& c){ center.y + ( camera_title_size.y / -2.0F ) + (rect_size_unit.y * (spacing * -3.0F)) ); draw_list->AddText(camera_title_min, col_white, camera_title.c_str()); - if(c->connected) { + if(c.connected) { int32_t SHUTTER_SPEED_ID = SHUTTER_SPEED_PHOTO_ID; int32_t ISO_MIN_ID = ISO_MIN_PHOTO_ID; int32_t ISO_MAX_ID = ISO_MAX_PHOTO_ID; @@ -231,7 +231,7 @@ void CameraListWindow::draw_group_header(const std::shared_ptr& c){ } } // Record Time - if(c->connected){ + if(c.connected){ ImVec2 frame_padding = ImVec2(10, 10); ImVec2 center = ImVec2( image_pos.x + (rect_size.x / 2.0F), @@ -253,7 +253,7 @@ void CameraListWindow::draw_group_header(const std::shared_ptr& c){ draw_list->AddText(record_time_min, col_white, record_time.c_str()); } // Preset mode - if(c->connected){ + if(c.connected){ int32_t preset; std::string preset_text; if(status[std::to_string(PRESET_ID)].is_number_integer()){ @@ -279,7 +279,7 @@ void CameraListWindow::draw_group_header(const std::shared_ptr& c){ ), col_white, preset_text.c_str()); } // Setting - if(c->connected){ + if(c.connected){ float spacing = 0.75F; float word_spacing = 10; std::string res; @@ -335,7 +335,7 @@ void CameraListWindow::draw_group_header(const std::shared_ptr& c){ ImGui::PopID(); ImGui::Dummy(rect_size); - bool is_select = state->current_camera_item == c->ip && state->current_camera_server == c->server; + bool is_select = state->current_camera_item == c.ip && state->current_camera_server == c.server; if(ImGui::IsItemHovered()){ std::string displayText = ""; displayText += "name: "; @@ -343,28 +343,28 @@ void CameraListWindow::draw_group_header(const std::shared_ptr& c){ displayText += "\n"; displayText += "server: "; - displayText += c->server; + displayText += c.server; displayText += "\n"; displayText += "ip: "; - displayText += c->ip; + displayText += c.ip; displayText += "\n"; displayText += "serial: "; - if(c->hw["serial_number"].is_string()){ - displayText += c->hw["serial_number"].get(); + if(c.hw.is_object() && c.hw["serial_number"].is_string()){ + displayText += c.hw["serial_number"].get(); } displayText += "\n"; displayText += "model: "; - if(c->hw["model_name"].is_string()){ - displayText += c->hw["model_name"].get(); + if(c.hw.is_object() && c.hw["model_name"].is_string()){ + displayText += c.hw["model_name"].get(); } displayText += "\n"; displayText += "firmware: "; - if(c->hw["firmware_version"].is_string()){ - displayText += c->hw["firmware_version"].get(); + if(c.hw.is_object() && c.hw["firmware_version"].is_string()){ + displayText += c.hw["firmware_version"].get(); } displayText += "\n"; ImGui::SetItemTooltip("%s", displayText.c_str()); diff --git a/src/master/windows/camera_list/display_state.cpp b/src/master/windows/camera_list/display_state.cpp index c7d6608b..1447ad29 100644 --- a/src/master/windows/camera_list/display_state.cpp +++ b/src/master/windows/camera_list/display_state.cpp @@ -1,426 +1,428 @@ #include "../camera_list.h" -void CameraListWindow::draw_group_state(const std::shared_ptr& c){ +void CameraListWindow::draw_group_state(const CameraInfo& c){ json status = json::object(); json setting = json::object(); int32_t preset = 0; - master->getStatusFromCamera(*c, status); - master->getSettingsFromCamera(*c, setting); + master->getStatusFromCamera(c, status); + master->getSettingsFromCamera(c, setting); ImGui::BeginGroup(); - ImGuiStyle& style = ImGui::GetStyle(); - float fontsize = ImGui::GetFontSize(); - std::string id = c->ip + "##Grid_Item_ID"; - std::string pid = c->ip + "##Grid_Popup_Item_ID"; - ImGui::PushID(id.c_str()); - - ImDrawList* draw_list = ImGui::GetWindowDrawList(); - ImVec2 image_pos = ImGui::GetCursorScreenPos(); - ImVec2 rect_size = get_rect_size(); - ImVec2 rect_size_unit = ImVec2(rect_size.x / 12.0F, rect_size.y / 12.0F); - - ImVec2 image_pos_max = image_pos + rect_size; - uint32_t col_white = IM_COL32(255, 255, 255, 255); - uint32_t col_grey = IM_COL32(210, 210, 210, 255); - uint32_t col_grey_light = IM_COL32(210, 210, 210, 50); - uint32_t col_red = IM_COL32(230, 10, 10, 255); - uint32_t col_orange = IM_COL32(230, 230, 10, 255); - uint32_t col_orange_dark = IM_COL32(80, 80, 10, 255); - uint32_t col_greed = IM_COL32(10, 230, 10, 255); - - // Get preset - { - if(status[std::to_string(PRESET_ID)].is_number_integer()){ - preset = status[std::to_string(PRESET_ID)].get(); + { + ImGuiStyle& style = ImGui::GetStyle(); + float fontsize = ImGui::GetFontSize(); + std::string id = c.ip + "##Grid_Item_ID"; + std::string pid = c.ip + "##Grid_Popup_Item_ID"; + ImGui::PushID(id.c_str()); + + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + ImVec2 image_pos = ImGui::GetCursorScreenPos(); + ImVec2 rect_size = get_rect_size(); + ImVec2 rect_size_unit = ImVec2(rect_size.x / 12.0F, rect_size.y / 12.0F); + + ImVec2 image_pos_max = image_pos + rect_size; + uint32_t col_white = IM_COL32(255, 255, 255, 255); + uint32_t col_grey = IM_COL32(210, 210, 210, 255); + uint32_t col_grey_light = IM_COL32(210, 210, 210, 50); + uint32_t col_red = IM_COL32(230, 10, 10, 255); + uint32_t col_orange = IM_COL32(230, 230, 10, 255); + uint32_t col_orange_dark = IM_COL32(80, 80, 10, 255); + uint32_t col_greed = IM_COL32(10, 230, 10, 255); + + // Get preset + { + if(status[std::to_string(PRESET_ID)].is_number_integer()){ + preset = status[std::to_string(PRESET_ID)].get(); + } } - } - // Drawing outline - { - uint32_t col = col_red; - if(c->connected) col = col_greed; - draw_list->AddRect(image_pos + ImVec2(5, 5), image_pos_max - ImVec2(5, 5), col, 2.0F, 0, 2.0F); - } - // Drawing Battery - if(c->connected){ - bool batteryHave = false; - bool batteryCharging = false; - int precentage = 0; - uint32_t col_inner_color; - if(status[std::to_string(BATTERY_PRESENT_ID)].is_number()){ - batteryHave = status[std::to_string(BATTERY_PRESENT_ID)].get() == 1; - } - if(status[std::to_string(INTERNAL_BATTERY_PERCENTAGE_ID)].is_number()){ - precentage = status[std::to_string(INTERNAL_BATTERY_PERCENTAGE_ID)].get(); - } - if(status[std::to_string(INTERNAL_BATTERY_BARS_ID)].is_number()){ - batteryCharging = status[std::to_string(INTERNAL_BATTERY_BARS_ID)].get() == 4; + // Drawing outline + { + uint32_t col = col_red; + if(c.connected) col = col_greed; + draw_list->AddRect(image_pos + ImVec2(5, 5), image_pos_max - ImVec2(5, 5), col, 2.0F, 0, 2.0F); } - ImVec2 battery_text_size; - std::string battery_text; - if(batteryHave){ - if(precentage <= 25){ - col_inner_color = col_orange; + // Drawing Battery + if(c.connected){ + bool batteryHave = false; + bool batteryCharging = false; + int precentage = 0; + uint32_t col_inner_color; + if(status[std::to_string(BATTERY_PRESENT_ID)].is_number()){ + batteryHave = status[std::to_string(BATTERY_PRESENT_ID)].get() == 1; + } + if(status[std::to_string(INTERNAL_BATTERY_PERCENTAGE_ID)].is_number()){ + precentage = status[std::to_string(INTERNAL_BATTERY_PERCENTAGE_ID)].get(); + } + if(status[std::to_string(INTERNAL_BATTERY_BARS_ID)].is_number()){ + batteryCharging = status[std::to_string(INTERNAL_BATTERY_BARS_ID)].get() == 4; + } + ImVec2 battery_text_size; + std::string battery_text; + if(batteryHave){ + if(precentage <= 25){ + col_inner_color = col_orange; + }else{ + col_inner_color = col_greed; + } + battery_text = std::to_string(precentage) + "%"; }else{ - col_inner_color = col_greed; + col_inner_color = col_red; + battery_text = "X"; + } + battery_text_size = ImGui::CalcTextSize(battery_text.c_str()); + ImVec2 bettery_size = ImVec2(rect_size_unit.x * 2.2, rect_size_unit.y * 1.2F); + ImVec2 frame_padding = ImVec2(10, 10); + ImVec2 inner_padding = ImVec2(2, 2); + int32_t spacing = 15; + + // Drawing Battery outline + ImVec2 outter_min = image_pos + ImVec2(rect_size.x - (frame_padding.x + bettery_size.x), frame_padding.y); + ImVec2 outter_max = image_pos + ImVec2(rect_size.x - frame_padding.x, frame_padding.y + bettery_size.y); + draw_list->AddRectFilled( + outter_min, + outter_max, + col_grey); + + // Drawing Battery inline + ImVec2 inner_min = outter_min + inner_padding; + ImVec2 inner_max = outter_max - inner_padding; + float w = inner_max.y - inner_min.y; + float wc = w * (precentage / 100.0F); + float wr = w - wc; + inner_max.x -= wr; + draw_list->AddRectFilled( + inner_min, + inner_max, + col_inner_color); + + // Drawing Battery text + ImVec2 text_pos = ImVec2(outter_max.x - battery_text_size.x, outter_max.y); + draw_list->AddText(text_pos, col_white, battery_text.c_str()); + + if(batteryCharging){ + std::string charging_text = "C=>"; + ImVec2 charging_text_size = ImGui::CalcTextSize(charging_text.c_str()); + ImVec2 charging_text_pos = ImVec2(inner_min.x, + ((inner_max.y + inner_min.y) / 2.0F) - (charging_text_size.y / 2.0F) + ); + draw_list->AddText(charging_text_pos, col_orange_dark, charging_text.c_str()); } - battery_text = std::to_string(precentage) + "%"; - }else{ - col_inner_color = col_red; - battery_text = "X"; - } - battery_text_size = ImGui::CalcTextSize(battery_text.c_str()); - ImVec2 bettery_size = ImVec2(rect_size_unit.x * 2.2, rect_size_unit.y * 1.2F); - ImVec2 frame_padding = ImVec2(10, 10); - ImVec2 inner_padding = ImVec2(2, 2); - int32_t spacing = 15; - - // Drawing Battery outline - ImVec2 outter_min = image_pos + ImVec2(rect_size.x - (frame_padding.x + bettery_size.x), frame_padding.y); - ImVec2 outter_max = image_pos + ImVec2(rect_size.x - frame_padding.x, frame_padding.y + bettery_size.y); - draw_list->AddRectFilled( - outter_min, - outter_max, - col_grey); - - // Drawing Battery inline - ImVec2 inner_min = outter_min + inner_padding; - ImVec2 inner_max = outter_max - inner_padding; - float w = inner_max.y - inner_min.y; - float wc = w * (precentage / 100.0F); - float wr = w - wc; - inner_max.x -= wr; - draw_list->AddRectFilled( - inner_min, - inner_max, - col_inner_color); - - // Drawing Battery text - ImVec2 text_pos = ImVec2(outter_max.x - battery_text_size.x, outter_max.y); - draw_list->AddText(text_pos, col_white, battery_text.c_str()); - - if(batteryCharging){ - std::string charging_text = "C=>"; - ImVec2 charging_text_size = ImGui::CalcTextSize(charging_text.c_str()); - ImVec2 charging_text_pos = ImVec2(inner_min.x, - ((inner_max.y + inner_min.y) / 2.0F) - (charging_text_size.y / 2.0F) - ); - draw_list->AddText(charging_text_pos, col_orange_dark, charging_text.c_str()); - } - } - // Drawing SD card - if(c->connected){ - bool sdHave = false; - int64_t remaining = 0; - uint32_t col_inner_color; - if(status[std::to_string(PRIMARY_STORAGE_ID)].is_number()){ - int b = status[std::to_string(PRIMARY_STORAGE_ID)].get() == 1; - if(b == 1) sdHave = true; - } - if(status[std::to_string(SD_CARD_REMAINING_ID)].is_number()){ - remaining = status[std::to_string(SD_CARD_REMAINING_ID)].get(); - } - ImVec2 sd_text_size; - std::string sd_text; - if(sdHave){ - col_inner_color = col_greed; - sd_text = bytesToGbString(remaining); - }else{ - col_inner_color = col_red; - sd_text = "X"; } - sd_text_size = ImGui::CalcTextSize(sd_text.c_str()); - ImVec2 sd_size = ImVec2(rect_size_unit.x * 2.2, rect_size_unit.y * 1.2F); - ImVec2 frame_padding = ImVec2(10, 10); - ImVec2 inner_padding = ImVec2(2, 2); - int32_t spacing = 15; - - // Drawing SD outline - ImVec2 outter_min = image_pos + frame_padding; - ImVec2 outter_max = image_pos + frame_padding + sd_size; - draw_list->AddRectFilled( - outter_min, - outter_max, - col_grey); - - // Drawing SD inline - ImVec2 inner_min = outter_min + inner_padding; - ImVec2 inner_max = outter_max - inner_padding; - draw_list->AddRectFilled( - inner_min, - inner_max, - col_inner_color); - - // Drawing SD text - ImVec2 text_pos = ImVec2(outter_min.x, outter_max.y); - draw_list->AddText(text_pos, col_white, sd_text.c_str()); - } - // Center text - { - std::string shutter_speed; - std::string ev_setting; - std::string camera_title = c->name; - std::string iso_setting; - std::string white_balance_setting; - std::string sharpness_setting; - std::string color_setting; - float spacing = 0.75F; - - ImVec2 camera_title_size = ImGui::CalcTextSize(camera_title.c_str()); - - // Draw Title in center - ImVec2 center = ImVec2( - image_pos.x + (rect_size.x / 2.0F), - image_pos.y + (rect_size.y / 2.0F) - ); - ImVec2 camera_title_min = ImVec2( - center.x + ( camera_title_size.x / -2.0F ), - center.y + ( camera_title_size.y / -2.0F ) + (rect_size_unit.y * (spacing * -3.0F)) - ); - draw_list->AddText(camera_title_min, col_white, camera_title.c_str()); - if(c->connected) { - int32_t SHUTTER_SPEED_ID = 0; - int32_t ISO_MIN_ID = 0; - int32_t ISO_MAX_ID = 0; - if(preset == 65538){ // Burst - SHUTTER_SPEED_ID = SHUTTER_SPEED_PHOTO_ID; - ISO_MIN_ID = ISO_MIN_BURST_ID; - ISO_MAX_ID = ISO_MAX_BURST_ID; + // Drawing SD card + if(c.connected){ + bool sdHave = false; + int64_t remaining = 0; + uint32_t col_inner_color; + if(status[std::to_string(PRIMARY_STORAGE_ID)].is_number()){ + int b = status[std::to_string(PRIMARY_STORAGE_ID)].get() == 1; + if(b == 1) sdHave = true; } - else if(preset == 65536){ // photo - SHUTTER_SPEED_ID = SHUTTER_SPEED_PHOTO_ID; - ISO_MIN_ID = ISO_MIN_PHOTO_ID; - ISO_MAX_ID = ISO_MAX_PHOTO_ID; + if(status[std::to_string(SD_CARD_REMAINING_ID)].is_number()){ + remaining = status[std::to_string(SD_CARD_REMAINING_ID)].get(); } - else if(preset == 0){ // video - SHUTTER_SPEED_ID = SHUTTER_SPEED_VIDEO_ID; - ISO_MIN_ID = ISO_MIN_VIDEO_ID; - ISO_MAX_ID = ISO_MAX_VIDEO_ID; + ImVec2 sd_text_size; + std::string sd_text; + if(sdHave){ + col_inner_color = col_greed; + sd_text = bytesToGbString(remaining); + }else{ + col_inner_color = col_red; + sd_text = "X"; } - else{ // Timelapse + sd_text_size = ImGui::CalcTextSize(sd_text.c_str()); + ImVec2 sd_size = ImVec2(rect_size_unit.x * 2.2, rect_size_unit.y * 1.2F); + ImVec2 frame_padding = ImVec2(10, 10); + ImVec2 inner_padding = ImVec2(2, 2); + int32_t spacing = 15; + + // Drawing SD outline + ImVec2 outter_min = image_pos + frame_padding; + ImVec2 outter_max = image_pos + frame_padding + sd_size; + draw_list->AddRectFilled( + outter_min, + outter_max, + col_grey); - } + // Drawing SD inline + ImVec2 inner_min = outter_min + inner_padding; + ImVec2 inner_max = outter_max - inner_padding; + draw_list->AddRectFilled( + inner_min, + inner_max, + col_inner_color); + + // Drawing SD text + ImVec2 text_pos = ImVec2(outter_min.x, outter_max.y); + draw_list->AddText(text_pos, col_white, sd_text.c_str()); + } + // Center text + { + std::string shutter_speed; + std::string ev_setting; + std::string camera_title = c.name; + std::string iso_setting; + std::string white_balance_setting; + std::string sharpness_setting; + std::string color_setting; + float spacing = 0.75F; + + ImVec2 camera_title_size = ImGui::CalcTextSize(camera_title.c_str()); + + // Draw Title in center + ImVec2 center = ImVec2( + image_pos.x + (rect_size.x / 2.0F), + image_pos.y + (rect_size.y / 2.0F) + ); + ImVec2 camera_title_min = ImVec2( + center.x + ( camera_title_size.x / -2.0F ), + center.y + ( camera_title_size.y / -2.0F ) + (rect_size_unit.y * (spacing * -3.0F)) + ); + draw_list->AddText(camera_title_min, col_white, camera_title.c_str()); + if(c.connected) { + int32_t SHUTTER_SPEED_ID = 0; + int32_t ISO_MIN_ID = 0; + int32_t ISO_MAX_ID = 0; + if(preset == 65538){ // Burst + SHUTTER_SPEED_ID = SHUTTER_SPEED_PHOTO_ID; + ISO_MIN_ID = ISO_MIN_BURST_ID; + ISO_MAX_ID = ISO_MAX_BURST_ID; + } + else if(preset == 65536){ // photo + SHUTTER_SPEED_ID = SHUTTER_SPEED_PHOTO_ID; + ISO_MIN_ID = ISO_MIN_PHOTO_ID; + ISO_MAX_ID = ISO_MAX_PHOTO_ID; + } + else if(preset == 0){ // video + SHUTTER_SPEED_ID = SHUTTER_SPEED_VIDEO_ID; + ISO_MIN_ID = ISO_MIN_VIDEO_ID; + ISO_MAX_ID = ISO_MAX_VIDEO_ID; + } + else{ // Timelapse + + } - if(setting[std::to_string(EXPOSURE_ID)].is_number_integer()){ - int32_t re = setting[std::to_string(EXPOSURE_ID)].get(); - ev_setting = EXPOSURE_STRING[re]; - } - if(setting[std::to_string(SHUTTER_SPEED_ID)].is_number_integer()){ - int32_t re = setting[std::to_string(SHUTTER_SPEED_ID)].get(); - if(preset == 0){ // Video - shutter_speed = SHUTTER_SPEED_VIDEO_STRING[re]; - }else { - shutter_speed = SHUTTER_SPEED_PHOTO_STRING[re]; + if(setting[std::to_string(EXPOSURE_ID)].is_number_integer()){ + int32_t re = setting[std::to_string(EXPOSURE_ID)].get(); + ev_setting = EXPOSURE_STRING[re]; } - if(shutter_speed == "Auto"){ - shutter_speed = "S: " + shutter_speed + ", " + ev_setting; - }else{ - shutter_speed = "S: " + shutter_speed; + if(setting[std::to_string(SHUTTER_SPEED_ID)].is_number_integer()){ + int32_t re = setting[std::to_string(SHUTTER_SPEED_ID)].get(); + if(preset == 0){ // Video + shutter_speed = SHUTTER_SPEED_VIDEO_STRING[re]; + }else { + shutter_speed = SHUTTER_SPEED_PHOTO_STRING[re]; + } + if(shutter_speed == "Auto"){ + shutter_speed = "S: " + shutter_speed + ", " + ev_setting; + }else{ + shutter_speed = "S: " + shutter_speed; + } } - } - if(setting[std::to_string(ISO_MIN_ID)].is_number() && setting[std::to_string(ISO_MAX_ID)].is_number()){ - int32_t iso_min = setting[std::to_string(ISO_MIN_ID)].get(); - int32_t iso_max = setting[std::to_string(ISO_MAX_ID)].get(); - std::string iso_min_text = "ISO MIN"; - std::string iso_max_text = "ISO MAX"; - if(preset == 0){ - iso_min_text = ISO_MIN_VIDEO_STRING[iso_min]; - iso_max_text = ISO_MAX_VIDEO_STRING[iso_max]; - }else{ - iso_min_text = ISO_MIN_PHOTO_STRING[iso_min]; - iso_max_text = ISO_MAX_PHOTO_STRING[iso_max]; + if(setting[std::to_string(ISO_MIN_ID)].is_number() && setting[std::to_string(ISO_MAX_ID)].is_number()){ + int32_t iso_min = setting[std::to_string(ISO_MIN_ID)].get(); + int32_t iso_max = setting[std::to_string(ISO_MAX_ID)].get(); + std::string iso_min_text = "ISO MIN"; + std::string iso_max_text = "ISO MAX"; + if(preset == 0){ + iso_min_text = ISO_MIN_VIDEO_STRING[iso_min]; + iso_max_text = ISO_MAX_VIDEO_STRING[iso_max]; + }else{ + iso_min_text = ISO_MIN_PHOTO_STRING[iso_min]; + iso_max_text = ISO_MAX_PHOTO_STRING[iso_max]; + } + iso_setting = "I: " + iso_min_text + " " + iso_max_text; + } + if(setting[std::to_string(SHARPNESS_ID)].is_number()){ + int32_t sharpness_bal = setting[std::to_string(SHARPNESS_ID)].get(); + sharpness_setting = SHARPNESS_STRING[sharpness_bal]; + } + if(setting[std::to_string(COLOR_ID)].is_number()){ + int32_t color_bal = setting[std::to_string(COLOR_ID)].get(); + color_setting = COLOR_STRING[color_bal]; } - iso_setting = "I: " + iso_min_text + " " + iso_max_text; + if(setting[std::to_string(WHITE_BALANCE_ID)].is_number()){ + int32_t white_bal = setting[std::to_string(WHITE_BALANCE_ID)].get(); + white_balance_setting = WHITE_BALANCE_STRING[white_bal]; + white_balance_setting += ", " + sharpness_setting + ", " + color_setting; + } + + ImVec2 shutter_speed_size = ImGui::CalcTextSize(shutter_speed.c_str()); + ImVec2 shutter_speed_min = ImVec2( + center.x + ( shutter_speed_size.x / -2.0F ), + center.y + ( shutter_speed_size.y / -2.0F ) + (rect_size_unit.y * (spacing * -1.0F)) + ); + draw_list->AddText(shutter_speed_min, col_white, shutter_speed.c_str()); + + ImVec2 iso_setting_size = ImGui::CalcTextSize(iso_setting.c_str()); + ImVec2 iso_setting_min = ImVec2( + center.x + ( iso_setting_size.x / -2.0F ), + center.y + ( iso_setting_size.y / -2.0F ) + (rect_size_unit.y * (spacing * 1.0F)) + ); + draw_list->AddText(iso_setting_min, col_white, iso_setting.c_str()); + + ImVec2 white_balance_setting_size = ImGui::CalcTextSize(white_balance_setting.c_str()); + ImVec2 white_balance_setting_min = ImVec2( + center.x + ( white_balance_setting_size.x / -2.0F ), + center.y + ( white_balance_setting_size.y / -2.0F ) + (rect_size_unit.y * (spacing * 3.0F)) + ); + draw_list->AddText(white_balance_setting_min, col_white, white_balance_setting.c_str()); + } + } + // Record Time + if(c.connected){ + ImVec2 frame_padding = ImVec2(10, 10); + ImVec2 center = ImVec2( + image_pos.x + (rect_size.x / 2.0F), + image_pos.y + (rect_size.y / 2.0F) + ); + + std::string record_time; + + if(status[std::to_string(VIDEO_ENCODING_DURATION_ID)].is_number_integer()){ + int32_t re = status[std::to_string(VIDEO_ENCODING_DURATION_ID)].get(); + record_time = toTimeCode(re); + } + + ImVec2 record_time_size = ImGui::CalcTextSize(record_time.c_str()); + ImVec2 record_time_min = ImVec2( + center.x + ( record_time_size.x / -2.0F ), + image_pos.y + frame_padding.y + ); + draw_list->AddText(record_time_min, col_white, record_time.c_str()); + } + // Preset mode + if(c.connected){ + int32_t preset; + std::string preset_text; + if(status[std::to_string(PRESET_ID)].is_number_integer()){ + preset = status[std::to_string(PRESET_ID)].get(); } - if(setting[std::to_string(SHARPNESS_ID)].is_number()){ - int32_t sharpness_bal = setting[std::to_string(SHARPNESS_ID)].get(); - sharpness_setting = SHARPNESS_STRING[sharpness_bal]; + + if(preset == GOPRO_MODE_VALUE[0]) preset_text = "V"; + else if(preset == GOPRO_MODE_VALUE[1]) preset_text = "PB"; + else if(preset == GOPRO_MODE_VALUE[2]) preset_text = "PS"; + else if(preset == GOPRO_MODE_VALUE[3]) preset_text = "T"; + else if(preset == GOPRO_MODE_VALUE[4]) preset_text = "TT"; + else if(preset == GOPRO_MODE_VALUE[5]) preset_text = "TLP"; + else if(preset == GOPRO_MODE_VALUE[6]) preset_text = "TLT"; + else if(preset == GOPRO_MODE_VALUE[7]) preset_text = "TV"; + else if(preset == GOPRO_MODE_VALUE[8]) preset_text = "TNV"; + else preset_text = std::to_string(preset); + + ImVec2 frame_padding = ImVec2(10, 10); + ImVec2 preset_text_size = ImGui::CalcTextSize(preset_text.c_str()); + draw_list->AddText(ImVec2( + image_pos.x + frame_padding.x, + (image_pos.y + rect_size.y) - (frame_padding.y + preset_text_size.y) + ), col_white, preset_text.c_str()); + } + // Setting + if(c.connected){ + float spacing = 0.75F; + float word_spacing = 10; + std::string res; + std::string fps; + std::string profile; + std::string videolen; + + if(setting[std::to_string(VIDEO_RESOLUTION_ID)].is_number_integer()){ + int32_t re = setting[std::to_string(VIDEO_RESOLUTION_ID)].get(); + res = VIDEO_RESOLUTION_STRING[re]; } - if(setting[std::to_string(COLOR_ID)].is_number()){ - int32_t color_bal = setting[std::to_string(COLOR_ID)].get(); - color_setting = COLOR_STRING[color_bal]; + if(setting[std::to_string(FRAMES_PER_SECOND_ID)].is_number_integer()){ + int32_t re = setting[std::to_string(FRAMES_PER_SECOND_ID)].get(); + fps = FRAMES_PER_SECOND_STRING[re]; } - if(setting[std::to_string(WHITE_BALANCE_ID)].is_number()){ - int32_t white_bal = setting[std::to_string(WHITE_BALANCE_ID)].get(); - white_balance_setting = WHITE_BALANCE_STRING[white_bal]; - white_balance_setting += ", " + sharpness_setting + ", " + color_setting; + if(setting[std::to_string(PROFILES_ID)].is_number_integer()){ + int32_t re = setting[std::to_string(PROFILES_ID)].get(); + profile = PROFILES_STRING[re]; + } + if(preset == 0){ + if(setting[std::to_string(VIDEO_LENS_ID)].is_number_integer()){ + int32_t re = setting[std::to_string(VIDEO_LENS_ID)].get(); + videolen = VIDEO_LENS_STRING[re]; + while(videolen.size() > 1){ + videolen.pop_back(); + } + } + }else{ + if(setting[std::to_string(PHOTO_LENS_ID)].is_number_integer()){ + int32_t re = setting[std::to_string(PHOTO_LENS_ID)].get(); + videolen = PHOTO_LENS_STRING[re]; + while(videolen.size() > 1){ + videolen.pop_back(); + } + } } - ImVec2 shutter_speed_size = ImGui::CalcTextSize(shutter_speed.c_str()); - ImVec2 shutter_speed_min = ImVec2( - center.x + ( shutter_speed_size.x / -2.0F ), - center.y + ( shutter_speed_size.y / -2.0F ) + (rect_size_unit.y * (spacing * -1.0F)) - ); - draw_list->AddText(shutter_speed_min, col_white, shutter_speed.c_str()); + ImVec2 res_text_size = ImGui::CalcTextSize(res.c_str()); + ImVec2 fps_text_size = ImGui::CalcTextSize(fps.c_str()); + ImVec2 profile_text_size = ImGui::CalcTextSize(profile.c_str()); + ImVec2 videolen_text_size = ImGui::CalcTextSize(videolen.c_str()); + ImVec2 frame_padding = ImVec2(5, 5); - ImVec2 iso_setting_size = ImGui::CalcTextSize(iso_setting.c_str()); - ImVec2 iso_setting_min = ImVec2( - center.x + ( iso_setting_size.x / -2.0F ), - center.y + ( iso_setting_size.y / -2.0F ) + (rect_size_unit.y * (spacing * 1.0F)) + ImVec2 corner = image_pos + rect_size; + ImVec2 profile_pos = ImVec2( + corner.x - (frame_padding.x + profile_text_size.x), + corner.y - (frame_padding.y + profile_text_size.y + ((rect_size_unit.y * 2.0F) * spacing)) ); - draw_list->AddText(iso_setting_min, col_white, iso_setting.c_str()); + draw_list->AddText(profile_pos, col_white, profile.c_str()); - ImVec2 white_balance_setting_size = ImGui::CalcTextSize(white_balance_setting.c_str()); - ImVec2 white_balance_setting_min = ImVec2( - center.x + ( white_balance_setting_size.x / -2.0F ), - center.y + ( white_balance_setting_size.y / -2.0F ) + (rect_size_unit.y * (spacing * 3.0F)) + ImVec2 framing_pos = ImVec2( + corner.x - (frame_padding.x + videolen_text_size.x), + corner.y - (frame_padding.y + videolen_text_size.y) ); - draw_list->AddText(white_balance_setting_min, col_white, white_balance_setting.c_str()); - } - } - // Record Time - if(c->connected){ - ImVec2 frame_padding = ImVec2(10, 10); - ImVec2 center = ImVec2( - image_pos.x + (rect_size.x / 2.0F), - image_pos.y + (rect_size.y / 2.0F) - ); - - std::string record_time; - - if(status[std::to_string(VIDEO_ENCODING_DURATION_ID)].is_number_integer()){ - int32_t re = status[std::to_string(VIDEO_ENCODING_DURATION_ID)].get(); - record_time = toTimeCode(re); - } + draw_list->AddText(framing_pos, col_white, videolen.c_str()); - ImVec2 record_time_size = ImGui::CalcTextSize(record_time.c_str()); - ImVec2 record_time_min = ImVec2( - center.x + ( record_time_size.x / -2.0F ), - image_pos.y + frame_padding.y - ); - draw_list->AddText(record_time_min, col_white, record_time.c_str()); - } - // Preset mode - if(c->connected){ - int32_t preset; - std::string preset_text; - if(status[std::to_string(PRESET_ID)].is_number_integer()){ - preset = status[std::to_string(PRESET_ID)].get(); - } + ImVec2 fps_pos = framing_pos - ImVec2(word_spacing + fps_text_size.x, 0); + draw_list->AddText(fps_pos, col_white, fps.c_str()); - if(preset == GOPRO_MODE_VALUE[0]) preset_text = "V"; - else if(preset == GOPRO_MODE_VALUE[1]) preset_text = "PB"; - else if(preset == GOPRO_MODE_VALUE[2]) preset_text = "PS"; - else if(preset == GOPRO_MODE_VALUE[3]) preset_text = "T"; - else if(preset == GOPRO_MODE_VALUE[4]) preset_text = "TT"; - else if(preset == GOPRO_MODE_VALUE[5]) preset_text = "TLP"; - else if(preset == GOPRO_MODE_VALUE[6]) preset_text = "TLT"; - else if(preset == GOPRO_MODE_VALUE[7]) preset_text = "TV"; - else if(preset == GOPRO_MODE_VALUE[8]) preset_text = "TNV"; - else preset_text = std::to_string(preset); - - ImVec2 frame_padding = ImVec2(10, 10); - ImVec2 preset_text_size = ImGui::CalcTextSize(preset_text.c_str()); - draw_list->AddText(ImVec2( - image_pos.x + frame_padding.x, - (image_pos.y + rect_size.y) - (frame_padding.y + preset_text_size.y) - ), col_white, preset_text.c_str()); - } - // Setting - if(c->connected){ - float spacing = 0.75F; - float word_spacing = 10; - std::string res; - std::string fps; - std::string profile; - std::string videolen; - - if(setting[std::to_string(VIDEO_RESOLUTION_ID)].is_number_integer()){ - int32_t re = setting[std::to_string(VIDEO_RESOLUTION_ID)].get(); - res = VIDEO_RESOLUTION_STRING[re]; - } - if(setting[std::to_string(FRAMES_PER_SECOND_ID)].is_number_integer()){ - int32_t re = setting[std::to_string(FRAMES_PER_SECOND_ID)].get(); - fps = FRAMES_PER_SECOND_STRING[re]; + ImVec2 res_pos = fps_pos - ImVec2(word_spacing + res_text_size.x, 0); + draw_list->AddText(res_pos, col_white, res.c_str()); } - if(setting[std::to_string(PROFILES_ID)].is_number_integer()){ - int32_t re = setting[std::to_string(PROFILES_ID)].get(); - profile = PROFILES_STRING[re]; - } - if(preset == 0){ - if(setting[std::to_string(VIDEO_LENS_ID)].is_number_integer()){ - int32_t re = setting[std::to_string(VIDEO_LENS_ID)].get(); - videolen = VIDEO_LENS_STRING[re]; - while(videolen.size() > 1){ - videolen.pop_back(); - } + + ImGui::PopID(); + ImGui::Dummy(rect_size); + bool is_select = state->current_camera_item == c.ip && state->current_camera_server == c.server; + if(ImGui::IsItemHovered()){ + std::string displayText = ""; + displayText += "name: "; + displayText += state->current_camera_name; + displayText += "\n"; + + displayText += "server: "; + displayText += c.server; + displayText += "\n"; + + displayText += "ip: "; + displayText += c.ip; + displayText += "\n"; + + displayText += "serial: "; + if(c.hw.is_object() && c.hw.contains("serial_number") && c.hw["serial_number"].is_string()){ + displayText += c.hw["serial_number"].get(); } - }else{ - if(setting[std::to_string(PHOTO_LENS_ID)].is_number_integer()){ - int32_t re = setting[std::to_string(PHOTO_LENS_ID)].get(); - videolen = PHOTO_LENS_STRING[re]; - while(videolen.size() > 1){ - videolen.pop_back(); - } - } - } + displayText += "\n"; - ImVec2 res_text_size = ImGui::CalcTextSize(res.c_str()); - ImVec2 fps_text_size = ImGui::CalcTextSize(fps.c_str()); - ImVec2 profile_text_size = ImGui::CalcTextSize(profile.c_str()); - ImVec2 videolen_text_size = ImGui::CalcTextSize(videolen.c_str()); - ImVec2 frame_padding = ImVec2(5, 5); - - ImVec2 corner = image_pos + rect_size; - ImVec2 profile_pos = ImVec2( - corner.x - (frame_padding.x + profile_text_size.x), - corner.y - (frame_padding.y + profile_text_size.y + ((rect_size_unit.y * 2.0F) * spacing)) - ); - draw_list->AddText(profile_pos, col_white, profile.c_str()); - - ImVec2 framing_pos = ImVec2( - corner.x - (frame_padding.x + videolen_text_size.x), - corner.y - (frame_padding.y + videolen_text_size.y) - ); - draw_list->AddText(framing_pos, col_white, videolen.c_str()); - - ImVec2 fps_pos = framing_pos - ImVec2(word_spacing + fps_text_size.x, 0); - draw_list->AddText(fps_pos, col_white, fps.c_str()); - - ImVec2 res_pos = fps_pos - ImVec2(word_spacing + res_text_size.x, 0); - draw_list->AddText(res_pos, col_white, res.c_str()); - } - - ImGui::PopID(); - ImGui::Dummy(rect_size); - bool is_select = state->current_camera_item == c->ip && state->current_camera_server == c->server; - if(ImGui::IsItemHovered()){ - std::string displayText = ""; - displayText += "name: "; - displayText += state->current_camera_name; - displayText += "\n"; - - displayText += "server: "; - displayText += c->server; - displayText += "\n"; - - displayText += "ip: "; - displayText += c->ip; - displayText += "\n"; - - displayText += "serial: "; - if(c->hw["serial_number"].is_string()){ - displayText += c->hw["serial_number"].get(); - } - displayText += "\n"; + displayText += "model: "; + if(c.hw.is_object() && c.hw.contains("model_name") && c.hw["model_name"].is_string()){ + displayText += c.hw["model_name"].get(); + } + displayText += "\n"; - displayText += "model: "; - if(c->hw["model_name"].is_string()){ - displayText += c->hw["model_name"].get(); + displayText += "firmware: "; + if(c.hw.is_object() && c.hw.contains("firmware_version") && c.hw["firmware_version"].is_string()){ + displayText += c.hw["firmware_version"].get(); + } + displayText += "\n"; + ImGui::SetItemTooltip("%s", displayText.c_str()); + draw_list->AddRect(image_pos, image_pos_max, col_grey, 2.0F, 0, 5.0F); } - displayText += "\n"; - - displayText += "firmware: "; - if(c->hw["firmware_version"].is_string()){ - displayText += c->hw["firmware_version"].get(); + else if(is_select){ + draw_list->AddRect(image_pos, image_pos_max, col_grey_light, 2.0F, 0, 5.0F); } - displayText += "\n"; - ImGui::SetItemTooltip("%s", displayText.c_str()); - draw_list->AddRect(image_pos, image_pos_max, col_grey, 2.0F, 0, 5.0F); - } - else if(is_select){ - draw_list->AddRect(image_pos, image_pos_max, col_grey_light, 2.0F, 0, 5.0F); + item_event(c); } - item_event( c); ImGui::EndGroup(); } From bbaae8a71eca9fc780ed6cc53bd3d150e4dcf423 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Tue, 5 May 2026 14:24:03 +0800 Subject: [PATCH 32/64] Fixed copy optimization Fixed name rule issue --- src/master/GoProMaster.cpp | 28 +++++++++++++-------- src/master/GoProMaster.h | 2 +- src/master/popup/preview/decode.cpp | 7 +++--- src/master/popup/preview/preview_popwin.cpp | 7 +++--- src/master/popup/preview_popwin.h | 8 +++--- src/master/windows/inspector.h | 8 +++--- src/master/windows/inspector/command.cpp | 2 +- src/master/windows/inspector/inspector.cpp | 7 +++--- src/master/windows/inspector/setting.cpp | 22 ++++++++-------- 9 files changed, 48 insertions(+), 43 deletions(-) diff --git a/src/master/GoProMaster.cpp b/src/master/GoProMaster.cpp index 686f7059..5fcb0de2 100644 --- a/src/master/GoProMaster.cpp +++ b/src/master/GoProMaster.cpp @@ -294,26 +294,33 @@ void GoProMaster::download_last_media(const std::string ip, const DownloadMediaP for(auto& s : cameras){ if(!s->connected) continue; if(ip.size() > 0 && s->ip != ip) continue; - std::string filename = s->name + fs::path(s->last_media).extension().string(); + std::string ext = fs::path(s->last_media).extension().string(); + std::string filename = s->name; if(filename.size() == 0 || s->name.size() == 0) { std::cerr << "[download_last_media] filename size is 0, we just skip..." << std::endl; continue; } size_t filename_size = filename.size(); + std::cout << "[download_last_media] \ttype: " << params.type << std::endl; + std::cout << "[download_last_media] \tfilename: " << filename.c_str() << std::endl; if(params.c_count > 0){ std::string ccc = ""; - if(params.type == 1){ - filename.reserve(); - } for(int32_t i = 0; i < params.c_count && i < filename_size; i++){ - ccc += filename.at(filename.size() - 1); - filename.pop_back(); + if(params.type == 1){ + ccc += filename.at(0); + filename.erase(filename.begin()); + } + if(params.type == 2){ + ccc += filename.at(filename.size() - 1); + filename.erase(filename.begin() + filename.size() - 1); + } } if(params.type == 2){ ccc.reserve(); } filename = ccc; } + filename += ext; bool islocal = s->server == "127.0.0.1"; json data = json::object(); @@ -405,19 +412,19 @@ void GoProMaster::applyAll(const std::string& ip, const json& res){ }).detach(); } -void GoProMaster::quickApplyAll(const std::shared_ptr& target){ - int32_t model = InspectorWindow::_get_current_model(target->hw); +void GoProMaster::quickApplyAll(const CameraInfo& target){ + int32_t model = InspectorWindow::_get_current_model(target.hw); json root = json::object(); json _set = json::object(); json _status = json::object(); - if(getSettingsFromCamera(*target, _set) && getStatusFromCamera(*target, _status)){ + if(getSettingsFromCamera(target, _set) && getStatusFromCamera(target, _status)){ // Execute the apply logic here int32_t p = _status[std::to_string(PRESET_ID)].get(); root["model"] = model; // Added a model field for mark it's supported root["preset"] = p; root["setting"] = _set; std::cout << "trying apply all, preset: " << p << std::endl; - applyAll(target->ip, root); + applyAll(target.ip, root); } } @@ -1067,6 +1074,7 @@ int32_t GoProMaster::findServer(const std::string ip){ int32_t GoProMaster::findCamera(const std::string server, const std::string ip){ int32_t index = 0; + //std::lock_guard lock(camera_mtx); for(const auto& c : cameras){ if(c->server == server && c->ip == ip){ return index; diff --git a/src/master/GoProMaster.h b/src/master/GoProMaster.h index 9893f626..bb14297a 100644 --- a/src/master/GoProMaster.h +++ b/src/master/GoProMaster.h @@ -102,7 +102,7 @@ class GoProMaster { int32_t haslocate(const std::string server, const std::string target); void apply(const std::string& ip, const std::string& target, const int32_t id, const int32_t value); void applyAll(const std::string& ip, const json& res); - void quickApplyAll(const std::shared_ptr& target); + void quickApplyAll(const CameraInfo& target); bool directoryExists(const std::string& path); diff --git a/src/master/popup/preview/decode.cpp b/src/master/popup/preview/decode.cpp index 38098657..71e64f28 100644 --- a/src/master/popup/preview/decode.cpp +++ b/src/master/popup/preview/decode.cpp @@ -16,7 +16,6 @@ void PreviewPopup::update_decoder(){ } { - std::lock_guard lock(master->camera_mtx); s = master->findCamera(state->preview_server, state->preview_ip); if(s == -1){ @@ -24,10 +23,10 @@ void PreviewPopup::update_decoder(){ trying = false; return; } - const std::shared_ptr& c = master->getCameras().at(s); - model = _get_current_model(c->hw); + const CameraInfo c = master->getCamera_Clone(s); + model = _get_current_model(c.hw); json buffer_setting = json::object(); - master->getSettingsFromCamera(*c, buffer_setting); + master->getSettingsFromCamera(c, buffer_setting); } if(gl_texture != 0){ diff --git a/src/master/popup/preview/preview_popwin.cpp b/src/master/popup/preview/preview_popwin.cpp index 3991b7f5..67294ec2 100644 --- a/src/master/popup/preview/preview_popwin.cpp +++ b/src/master/popup/preview/preview_popwin.cpp @@ -48,11 +48,11 @@ void PreviewPopup::set_window_data(json data){ } } -void PreviewPopup::register_setting_drawer(std::function& state, std::shared_ptr& master, const std::shared_ptr& c)> caller){ +void PreviewPopup::register_setting_drawer(std::function& state, std::shared_ptr& master, const CameraInfo& c)> caller){ setting_drawer = caller; } -void PreviewPopup::register_protune_drawer(std::function& state, std::shared_ptr& master, const std::shared_ptr& c)> caller){ +void PreviewPopup::register_protune_drawer(std::function& state, std::shared_ptr& master, const CameraInfo& c)> caller){ protune_drawer = caller; } @@ -162,10 +162,9 @@ void PreviewPopup::_draw_bottom_button(){ void PreviewPopup::_draw_setting(){ if(setting_drawer != NULL){ int32_t s = -1; - std::lock_guard lock(master->camera_mtx); s = master->findCamera(state->preview_server, state->preview_ip); if(s != -1){ - const std::shared_ptr& c = master->getCameras().at(s); + const CameraInfo c = master->getCamera_Clone(s); if(ImGui::Button("Quick Apply All##Preview_Popwin_Action")){ state->applying_all = true; master->quickApplyAll(c); diff --git a/src/master/popup/preview_popwin.h b/src/master/popup/preview_popwin.h index a06d929f..efa37819 100644 --- a/src/master/popup/preview_popwin.h +++ b/src/master/popup/preview_popwin.h @@ -53,8 +53,8 @@ class PreviewPopup : public BasePopWindow { json get_window_data() override; void set_window_data(json data) override; - void register_setting_drawer(std::function& state, std::shared_ptr& master, const std::shared_ptr& c)> caller); - void register_protune_drawer(std::function& state, std::shared_ptr& master, const std::shared_ptr& c)> caller); + void register_setting_drawer(std::function& state, std::shared_ptr& master, const CameraInfo& c)> caller); + void register_protune_drawer(std::function& state, std::shared_ptr& master, const CameraInfo& c)> caller); virtual void trigger(bool value) override; virtual void update_decoder(); @@ -70,8 +70,8 @@ class PreviewPopup : public BasePopWindow { void _draw_setting(); private: - std::function& state, std::shared_ptr& master, const std::shared_ptr& c)> setting_drawer; - std::function& state, std::shared_ptr& master, const std::shared_ptr& c)> protune_drawer; + std::function& state, std::shared_ptr& master, const CameraInfo& c)> setting_drawer; + std::function& state, std::shared_ptr& master, const CameraInfo& c)> protune_drawer; cv::VideoCapture cap; std::string pipeline; std::queue frame_queue; diff --git a/src/master/windows/inspector.h b/src/master/windows/inspector.h index 09c0cc2d..03ec0a13 100644 --- a/src/master/windows/inspector.h +++ b/src/master/windows/inspector.h @@ -23,8 +23,8 @@ class InspectorWindow : public BaseWindow { virtual void draw_system(); virtual void draw_setting(); virtual void draw_protune(); - static void global_draw_setting(std::shared_ptr& state, std::shared_ptr& master, const std::shared_ptr& c); - static void global_draw_protune(std::shared_ptr& state, std::shared_ptr& master, const std::shared_ptr& c); + static void global_draw_setting(std::shared_ptr& state, std::shared_ptr& master, const CameraInfo& c); + static void global_draw_protune(std::shared_ptr& state, std::shared_ptr& master, const CameraInfo& c); virtual void draw_status(); virtual void draw_hardware(); virtual void draw_network(); @@ -41,8 +41,8 @@ class InspectorWindow : public BaseWindow { protected: virtual void _draw_setting(std::vector& ordered); virtual void _draw_status(std::vector& ordered); - static void _global_draw_setting(std::shared_ptr& state, std::shared_ptr& master, const std::shared_ptr& c, std::vector& ordered); - static bool _global_draw_setting_item(int32_t i, std::shared_ptr& state, std::shared_ptr& master, const std::shared_ptr& c, std::vector& ordered); + static void _global_draw_setting(std::shared_ptr& state, std::shared_ptr& master, const CameraInfo& c, std::vector& ordered); + static bool _global_draw_setting_item(int32_t i, std::shared_ptr& state, std::shared_ptr& master, const CameraInfo& c, std::vector& ordered); static bool conditional_filter(const std::shared_ptr& state, int32_t mymodel, int32_t setting_id); static bool conditional_filter_option(const std::shared_ptr& state, int32_t mymodel, int32_t setting_id, int32_t value_index); diff --git a/src/master/windows/inspector/command.cpp b/src/master/windows/inspector/command.cpp index b08a84e2..49c1b4e0 100644 --- a/src/master/windows/inspector/command.cpp +++ b/src/master/windows/inspector/command.cpp @@ -16,7 +16,7 @@ void InspectorWindow::draw_command_local(){ ImVec2 full_button_size = ImVec2(size.x - style.ItemSpacing.x, 0); if(current_camera != -1) { - CameraInfo info = *(master->getCameras().at(current_camera)); + CameraInfo info = master->getCamera_Clone(current_camera); if(ImGui::Button("Record", button_2size)) master->command_only(info.server, "shutter_on", info.ip); ImGui::SameLine(); if(ImGui::Button("Stop", button_2size)) master->command_only(info.server, "shutter_off", info.ip); diff --git a/src/master/windows/inspector/inspector.cpp b/src/master/windows/inspector/inspector.cpp index 95c85eb2..b04c5624 100644 --- a/src/master/windows/inspector/inspector.cpp +++ b/src/master/windows/inspector/inspector.cpp @@ -109,11 +109,10 @@ void InspectorWindow::set_window_data(json data) { void InspectorWindow::render(){ ImGui::Begin("Inspector", &enable, w_flag); { - std::lock_guard lock(master->camera_mtx); int32_t s = master->findCamera(state->current_camera_server, state->current_camera_item); if(s != -1){ - auto& c = master->getCameras().at(s); - should_disabled = !c->connected || state->current_camera_item.size() < 10 || s == -1 || !state->current_setting_items_bind; + CameraInfo c = master->getCamera_Clone(s); + should_disabled = !c.connected || state->current_camera_item.size() < 10 || s == -1 || !state->current_setting_items_bind; } draw_header(); @@ -152,7 +151,7 @@ void InspectorWindow::render(){ ImGui::BeginDisabled(should_disabled || state->applying_all); if(ImGui::Button("Quick Apply All##Inspector_Bar_Item")){ if(s != -1){ - const std::shared_ptr& c = master->getCameras().at(s); + const CameraInfo c = master->getCamera_Clone(s); master->quickApplyAll(c); state->applying_all = true; } diff --git a/src/master/windows/inspector/setting.cpp b/src/master/windows/inspector/setting.cpp index 48c18d91..48453671 100644 --- a/src/master/windows/inspector/setting.cpp +++ b/src/master/windows/inspector/setting.cpp @@ -35,9 +35,9 @@ void InspectorWindow::draw_protune(){ } } -void InspectorWindow::global_draw_setting(std::shared_ptr& state, std::shared_ptr& master, const std::shared_ptr& c){ +void InspectorWindow::global_draw_setting(std::shared_ptr& state, std::shared_ptr& master, const CameraInfo& c){ json status = json::object(); - master->getStatusFromCamera(*c, status); + master->getStatusFromCamera(c, status); if (status[std::to_string(PRESET_ID)].is_number()) { int32_t preset = status[std::to_string(PRESET_ID)].get(); if(preset == 0){ @@ -48,9 +48,9 @@ void InspectorWindow::global_draw_setting(std::shared_ptr& state, s } } -void InspectorWindow::global_draw_protune(std::shared_ptr& state, std::shared_ptr& master, const std::shared_ptr& c){ +void InspectorWindow::global_draw_protune(std::shared_ptr& state, std::shared_ptr& master, const CameraInfo& c){ json status = json::object(); - master->getStatusFromCamera(*c, status); + master->getStatusFromCamera(c, status); if (status[std::to_string(PRESET_ID)].is_number()) { int32_t preset = status[std::to_string(PRESET_ID)].get(); if(preset == 0){ @@ -64,7 +64,7 @@ void InspectorWindow::global_draw_protune(std::shared_ptr& state, s void InspectorWindow::_draw_setting(std::vector& ordered){ int32_t current = master->findCamera(state->current_camera_server, state->current_camera_item); if(current < 0) return; - auto& c = master->getCameras().at(current); + const CameraInfo c = master->getCamera_Clone(current); int32_t move_from = -1, move_to = -1; for(int32_t i = 0; i < ordered.size(); i++){ int32_t id = ordered[i]; @@ -105,23 +105,23 @@ void InspectorWindow::_draw_setting(std::vector& ordered){ } } -void InspectorWindow::_global_draw_setting(std::shared_ptr& state, std::shared_ptr& master, const std::shared_ptr& c, std::vector& ordered){ +void InspectorWindow::_global_draw_setting(std::shared_ptr& state, std::shared_ptr& master, const CameraInfo& c, std::vector& ordered){ for(int32_t i = 0; i < ordered.size(); i++){ _global_draw_setting_item(i, state, master, c, ordered); } } -bool InspectorWindow::_global_draw_setting_item(int32_t i, std::shared_ptr& state, std::shared_ptr& master, const std::shared_ptr& c, std::vector& ordered){ +bool InspectorWindow::_global_draw_setting_item(int32_t i, std::shared_ptr& state, std::shared_ptr& master, const CameraInfo& c, std::vector& ordered){ int32_t id = ordered[i]; std::string name = GET_SETTING_NAME_BY_ID(id); size_t size = GET_SETTING_SIZE_BY_ID(id); int32_t ava = GET_SETTING_AVA_BY_ID(id); - int32_t model_enum = _get_current_model(c->hw); + int32_t model_enum = _get_current_model(c.hw); json setting = json::object(); json status = json::object(); - master->getSettingsFromCamera(*c, setting); - master->getStatusFromCamera(*c, status); + master->getSettingsFromCamera(c, setting); + master->getStatusFromCamera(c, status); if((model_enum&ava) == 0){ return false; @@ -170,7 +170,7 @@ bool InspectorWindow::_global_draw_setting_item(int32_t i, std::shared_ptrapply("", c->ip, id, values_id[n]); + master->apply("", c.ip, id, values_id[n]); } if (is_selected) ImGui::SetItemDefaultFocus(); // You may set the initial focus when opening the combo (scrolling + for keyboard navigation support) From bdc21da201a325ebab03ca4b15445bbe3c07f53d Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Tue, 5 May 2026 14:28:15 +0800 Subject: [PATCH 33/64] Update package versions --- package/deb_master_amd64 | 2 +- package/deb_server_amd64 | 2 +- package/deb_server_arm64 | 2 +- package/win_master_x64.iss | 2 +- package/win_server_x64.iss | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package/deb_master_amd64 b/package/deb_master_amd64 index f3034ff3..2d4b0a1d 100644 --- a/package/deb_master_amd64 +++ b/package/deb_master_amd64 @@ -1,5 +1,5 @@ Package: go-pro-control-master -Version: 1.0.1 +Version: 1.0.5 Section: shells Priority: optional Architecture: amd64 diff --git a/package/deb_server_amd64 b/package/deb_server_amd64 index 74a673cf..1b9e4306 100644 --- a/package/deb_server_amd64 +++ b/package/deb_server_amd64 @@ -1,5 +1,5 @@ Package: go-pro-control-server -Version: 1.0.1 +Version: 1.0.5 Section: shells Priority: optional Architecture: amd64 diff --git a/package/deb_server_arm64 b/package/deb_server_arm64 index 8cc0fde1..efad9912 100644 --- a/package/deb_server_arm64 +++ b/package/deb_server_arm64 @@ -1,5 +1,5 @@ Package: go-pro-control-server -Version: 1.0.1 +Version: 1.0.5 Section: shells Priority: optional Architecture: arm64 diff --git a/package/win_master_x64.iss b/package/win_master_x64.iss index 663cf21a..3a1f1ee0 100755 --- a/package/win_master_x64.iss +++ b/package/win_master_x64.iss @@ -3,7 +3,7 @@ ; Non-commercial use only #define MyAppName "GoPro Master" -#define MyAppVersion "0.1.3" +#define MyAppVersion "1.0.5" #define MyAppPublisher "Elly" #define MyAppURL "https://github.com/Elly2018/GoPro_Controller" #define MyAppExeName "go-pro-master.exe" diff --git a/package/win_server_x64.iss b/package/win_server_x64.iss index 90db7aeb..4853d8c9 100755 --- a/package/win_server_x64.iss +++ b/package/win_server_x64.iss @@ -3,7 +3,7 @@ ; Non-commercial use only #define MyAppName "GoPro Server" -#define MyAppVersion "0.1.3" +#define MyAppVersion "1.0.5" #define MyAppPublisher "Elly" #define MyAppURL "https://github.com/Elly2018/GoPro_Controller" #define MyAppExeName "go-pro-server.exe" From 02bfec044f60ca9e7dcb38dd6544dff72dffaf06 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Tue, 5 May 2026 14:33:18 +0800 Subject: [PATCH 34/64] First Commit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 21b18b12..ac4f6417 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # GoPro Controller Tool for control multiple GoPro Cameras, The design is for above 100 cameras connection. - + [Documentation](https://github.com/Elly2018/GoPro_Controller/wiki) ## Application Requirement From be412a5d5f5a7647a55dd35013e143813640ba8b Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Tue, 5 May 2026 14:40:08 +0800 Subject: [PATCH 35/64] Added media browser popwin frame --- src/master/main.cpp | 4 +++- src/master/popup/media_browser_popwin cpp | 15 +++++++++++++++ src/master/popup/media_browser_popwin.h | 16 ++++++++++++++++ src/master/popup/popwins.h | 3 ++- 4 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 src/master/popup/media_browser_popwin cpp create mode 100644 src/master/popup/media_browser_popwin.h diff --git a/src/master/main.cpp b/src/master/main.cpp index b72055a0..a7f7b662 100644 --- a/src/master/main.cpp +++ b/src/master/main.cpp @@ -45,7 +45,8 @@ std::shared_ptr start_webcam_popwin; std::shared_ptr preview_popwin; std::shared_ptr add_preset_popwin; std::shared_ptr preset_manager_popwin; -std::shared_ptr pop_windows_array[6]; +std::shared_ptr media_browser_popwin; +std::shared_ptr pop_windows_array[7]; // All the window flags ExecutionType execution_type = ExecutionType::SetAll; @@ -195,6 +196,7 @@ int main(int, char**) WIN_INIT2(preview_popwin, PreviewPopup, renderer, pop_windows_array, 3); WIN_INIT(add_preset_popwin, AddPresetPopup, pop_windows_array, 4); WIN_INIT(preset_manager_popwin, PresetManagerPopup, pop_windows_array, 5); + WIN_INIT(media_browser_popwin, MediaBrowserPopup, pop_windows_array, 6); // Register event for master master->registerCameraSettingFeedback(settingGetterFeedback); master->registerCameraStatusFeedback(statusGetterFeedback); diff --git a/src/master/popup/media_browser_popwin cpp b/src/master/popup/media_browser_popwin cpp new file mode 100644 index 00000000..93344fb9 --- /dev/null +++ b/src/master/popup/media_browser_popwin cpp @@ -0,0 +1,15 @@ +#include "media_browser_popwin.h" + +MediaBrowserPopup::MediaBrowserPopup( + std::shared_ptr _setting, + std::shared_ptr _state, + std::shared_ptr _master +) + : BasePopWindow(_setting, _state, _master) { + title = "Media Browser##Popup"; +} + + +MediaBrowserPopup::~MediaBrowserPopup(){ + +} \ No newline at end of file diff --git a/src/master/popup/media_browser_popwin.h b/src/master/popup/media_browser_popwin.h new file mode 100644 index 00000000..393decc7 --- /dev/null +++ b/src/master/popup/media_browser_popwin.h @@ -0,0 +1,16 @@ +#pragma once +#include "base_pop_window.h" + +class MediaBrowserPopup : public BasePopWindow { +public: + MediaBrowserPopup( + std::shared_ptr _setting, + std::shared_ptr _state, + std::shared_ptr _master); + ~MediaBrowserPopup(); + + //virtual void trigger(bool value) override; + //virtual void render() override; +private: + +}; \ No newline at end of file diff --git a/src/master/popup/popwins.h b/src/master/popup/popwins.h index 5a82afb5..3b5aadee 100644 --- a/src/master/popup/popwins.h +++ b/src/master/popup/popwins.h @@ -10,4 +10,5 @@ #include "scan_camera_popwin.h" #include "start_webcam_popwin.h" #include "add_preset_popwin.h" -#include "preset_manager_popwin.h" \ No newline at end of file +#include "preset_manager_popwin.h" +#include "media_browser_popwin.h" \ No newline at end of file From 4dfd2a3680b7dee37d9376b68cfbaf3c004bb47d Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Tue, 5 May 2026 14:45:24 +0800 Subject: [PATCH 36/64] Update media browser size and position calculation --- src/master/popup/add_camera_popwin.cpp | 16 +++++++--------- src/master/popup/media_browser_popwin cpp | 21 +++++++++++++++++++++ src/master/popup/media_browser_popwin.h | 2 +- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/master/popup/add_camera_popwin.cpp b/src/master/popup/add_camera_popwin.cpp index d4bef4bf..20570126 100644 --- a/src/master/popup/add_camera_popwin.cpp +++ b/src/master/popup/add_camera_popwin.cpp @@ -17,29 +17,27 @@ AddCameraPopup::~AddCameraPopup(){ void AddCameraPopup::trigger(bool value){ BasePopWindow::trigger(value); if(value){ - std::lock_guard lock(master->camera_mtx); - const std::vector>& refs = master->getServers(); + const std::vector refs = master->getServers_Clone(); if(refs.size() > 0){ - server_ip_buf = refs[0]->ip; + server_ip_buf = refs[0].ip; } } } void AddCameraPopup::render(){ if(ImGui::BeginPopupModal(title.c_str(), NULL, wp_flag)){ - std::lock_guard lock(master->camera_mtx); - const std::vector>& all_servers = master->getServers(); + const std::vector all_servers = master->getServers_Clone(); bool updated = false; if(ImGui::BeginCombo("Server IP", server_ip_buf.c_str())){ for (int n = 0; n < all_servers.size(); n++) { - std::string option = all_servers.at(n)->ip; + std::string option = all_servers.at(n).ip; bool is_selected = all_servers[n]->ip == server_ip_buf; option += "##PopupServerOption"; - ImGui::BeginDisabled(!all_servers[n]->connected); + ImGui::BeginDisabled(!all_servers[n].ip); if (ImGui::Selectable(option.c_str(), is_selected)) { - server_ip_buf = all_servers.at(n)->ip; + server_ip_buf = all_servers.at(n).ip; } ImGui::EndDisabled(); if (is_selected) @@ -63,7 +61,7 @@ void AddCameraPopup::render(){ error = "Server does not exist."; pass = false; } - if(!all_servers[index]->connected){ + if(!all_servers.at(index).connected){ error = "Server is disconnected."; pass = false; } diff --git a/src/master/popup/media_browser_popwin cpp b/src/master/popup/media_browser_popwin cpp index 93344fb9..011148e1 100644 --- a/src/master/popup/media_browser_popwin cpp +++ b/src/master/popup/media_browser_popwin cpp @@ -12,4 +12,25 @@ MediaBrowserPopup::MediaBrowserPopup( MediaBrowserPopup::~MediaBrowserPopup(){ +} + + +void MediaBrowserPopup::render(){ + ImGuiIO& io = ImGui::GetIO(); + ImGuiStyle& style = ImGui::GetStyle(); + ImVec2 display_size = io.DisplaySize; + ImVec2 unit = ImVec2(display_size.x / 12.0f, display_size.y / 12.0f); + float unit_width; + float unit_height; + + ImGui::SetNextWindowPos(ImVec2(unit.x * 1.0F, unit.y * 1.0F), wp_cond); + ImGui::SetNextWindowSize(ImVec2(unit.x * 10.0F, unit.y * 10.0F), wp_cond); + + unit_width = (unit.x * 10.0F) / 2.0F - style.ItemSpacing.x; + unit_height = unit.y * 8.5F; + + if(ImGui::BeginPopupModal(title.c_str(), NULL, wp_flag)){ + + ImGui::EndPopup(); + } } \ No newline at end of file diff --git a/src/master/popup/media_browser_popwin.h b/src/master/popup/media_browser_popwin.h index 393decc7..882cc4b3 100644 --- a/src/master/popup/media_browser_popwin.h +++ b/src/master/popup/media_browser_popwin.h @@ -10,7 +10,7 @@ class MediaBrowserPopup : public BasePopWindow { ~MediaBrowserPopup(); //virtual void trigger(bool value) override; - //virtual void render() override; + virtual void render() override; private: }; \ No newline at end of file From e8b5b2a924064bf048a9f2baa9b8b85c292d4103 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Tue, 5 May 2026 15:07:36 +0800 Subject: [PATCH 37/64] Fixed file extension issue --- src/master/popup/add_camera_popwin.cpp | 4 +-- ...er_popwin cpp => media_browser_popwin.cpp} | 25 ++++++++++++++++++- src/master/popup/media_browser_popwin.h | 5 ++-- 3 files changed, 29 insertions(+), 5 deletions(-) rename src/master/popup/{media_browser_popwin cpp => media_browser_popwin.cpp} (52%) diff --git a/src/master/popup/add_camera_popwin.cpp b/src/master/popup/add_camera_popwin.cpp index 20570126..5b271e75 100644 --- a/src/master/popup/add_camera_popwin.cpp +++ b/src/master/popup/add_camera_popwin.cpp @@ -32,9 +32,9 @@ void AddCameraPopup::render(){ for (int n = 0; n < all_servers.size(); n++) { std::string option = all_servers.at(n).ip; - bool is_selected = all_servers[n]->ip == server_ip_buf; + bool is_selected = all_servers.at(n).ip == server_ip_buf; option += "##PopupServerOption"; - ImGui::BeginDisabled(!all_servers[n].ip); + ImGui::BeginDisabled(!all_servers.at(n).connected); if (ImGui::Selectable(option.c_str(), is_selected)) { server_ip_buf = all_servers.at(n).ip; diff --git a/src/master/popup/media_browser_popwin cpp b/src/master/popup/media_browser_popwin.cpp similarity index 52% rename from src/master/popup/media_browser_popwin cpp rename to src/master/popup/media_browser_popwin.cpp index 011148e1..5bdb4f5c 100644 --- a/src/master/popup/media_browser_popwin cpp +++ b/src/master/popup/media_browser_popwin.cpp @@ -30,7 +30,30 @@ void MediaBrowserPopup::render(){ unit_height = unit.y * 8.5F; if(ImGui::BeginPopupModal(title.c_str(), NULL, wp_flag)){ - + { + int32_t s = master->findCamera(state->current_camera_server, state->current_camera_item); + if(s >= 0) { + const CameraInfo ci = master->getCamera_Clone(s); + ImGui::BeginChild("Header##Media_Browser_ChildWin_Header", ImVec2(unit.x * 10.0F, unit.y * 1.5F)); + { + draw_header(ci); + } + ImGui::EndChild(); + ImGui::BeginChild("Body##Media_Browser_ChildWin_Body", ImVec2(unit.x * 10.0F, unit.y * 7.0F)); + { + draw_body(ci); + } + ImGui::EndChild(); + } + } ImGui::EndPopup(); } +} + +void MediaBrowserPopup::draw_header(const CameraInfo& c){ + bool is_enable = c.ip.size() > 0; +} + +void MediaBrowserPopup::draw_body(const CameraInfo& c){ + if(c.ip.size() == 0) return; } \ No newline at end of file diff --git a/src/master/popup/media_browser_popwin.h b/src/master/popup/media_browser_popwin.h index 882cc4b3..766191a5 100644 --- a/src/master/popup/media_browser_popwin.h +++ b/src/master/popup/media_browser_popwin.h @@ -11,6 +11,7 @@ class MediaBrowserPopup : public BasePopWindow { //virtual void trigger(bool value) override; virtual void render() override; -private: - +protected: + virtual void draw_header(const CameraInfo& c); + virtual void draw_body(const CameraInfo& c); }; \ No newline at end of file From b550f793891b65b9f431df1dd044da287018a645 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Tue, 5 May 2026 15:24:21 +0800 Subject: [PATCH 38/64] Adjust the media browser --- src/master/main.cpp | 4 ++++ src/master/popup/media_browser_popwin.cpp | 10 +++++----- src/master/windows/inspector/media.cpp | 8 ++++++-- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/master/main.cpp b/src/master/main.cpp index a7f7b662..e3166189 100644 --- a/src/master/main.cpp +++ b/src/master/main.cpp @@ -83,6 +83,10 @@ void background_worker(){ preset_manager_popwin->trigger(true); std::cout << "Detect preset_manager popup" << std::endl; } + else if(cmd == "media_browser"){ + media_browser_popwin->trigger(true); + std::cout << "Detect media_browser popup" << std::endl; + } } std::this_thread::sleep_for(std::chrono::milliseconds(10)); } diff --git a/src/master/popup/media_browser_popwin.cpp b/src/master/popup/media_browser_popwin.cpp index 5bdb4f5c..ea919210 100644 --- a/src/master/popup/media_browser_popwin.cpp +++ b/src/master/popup/media_browser_popwin.cpp @@ -27,21 +27,21 @@ void MediaBrowserPopup::render(){ ImGui::SetNextWindowSize(ImVec2(unit.x * 10.0F, unit.y * 10.0F), wp_cond); unit_width = (unit.x * 10.0F) / 2.0F - style.ItemSpacing.x; - unit_height = unit.y * 8.5F; + unit_height = unit.y * 9.0F; if(ImGui::BeginPopupModal(title.c_str(), NULL, wp_flag)){ { int32_t s = master->findCamera(state->current_camera_server, state->current_camera_item); if(s >= 0) { const CameraInfo ci = master->getCamera_Clone(s); - ImGui::BeginChild("Header##Media_Browser_ChildWin_Header", ImVec2(unit.x * 10.0F, unit.y * 1.5F)); + ImGui::BeginChild("Body##Media_Browser_ChildWin_Body", ImVec2(unit.x * 10.0F - style.ItemSpacing.x, unit.y * 7.5F)); { - draw_header(ci); + draw_body(ci); } ImGui::EndChild(); - ImGui::BeginChild("Body##Media_Browser_ChildWin_Body", ImVec2(unit.x * 10.0F, unit.y * 7.0F)); + ImGui::BeginChild("Header##Media_Browser_ChildWin_Header", ImVec2(unit.x * 10.0F - style.ItemSpacing.x, unit.y * 1.6F)); { - draw_body(ci); + draw_header(ci); } ImGui::EndChild(); } diff --git a/src/master/windows/inspector/media.cpp b/src/master/windows/inspector/media.cpp index 34395198..9cc2fd9c 100644 --- a/src/master/windows/inspector/media.cpp +++ b/src/master/windows/inspector/media.cpp @@ -48,7 +48,7 @@ void InspectorWindow::draw_media_global(){ if(ImGui::InputText("Media Download", &state->current_download_location)){ state->update_server(); } - if(ImGui::Button("All Download", button_size)){ + if(ImGui::Button("All Download", button3_size)){ std::string buffer = state->current_download_location; while(buffer.size() > 0 && buffer.at(buffer.size() - 1) == '/'){ buffer.pop_back(); @@ -65,7 +65,7 @@ void InspectorWindow::draw_media_global(){ } if(ImGui::IsItemHovered()) ImGui::SetTooltip("Download all exist camera instances"); ImGui::SameLine(); - if(ImGui::Button("Single Download", button_size)){ + if(ImGui::Button("Single Download", button3_size)){ std::string buffer = state->current_download_location; while(buffer.size() > 0 && buffer.at(buffer.size() - 1) == '/'){ buffer.pop_back(); @@ -80,6 +80,10 @@ void InspectorWindow::draw_media_global(){ master->download_last_media(state->current_camera_item, params); } } + ImGui::SameLine(); + if(ImGui::Button("Media Browser", button3_size)){ + state->command_sender("media_browser"); + } if(ImGui::IsItemHovered()) ImGui::SetTooltip("Download current select camera instance"); if(ImGui::Button("Open Home", button3_size)){ From ad03a6202a3aa5667e30bff7cef98e1ceaff9d11 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Tue, 5 May 2026 15:57:12 +0800 Subject: [PATCH 39/64] Added server thumbnail entry point --- src/server/GoProController.h | 1 + src/server/controller/media.cpp | 6 +++++- src/server/main.cpp | 13 ++++++++++--- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/server/GoProController.h b/src/server/GoProController.h index e999c663..197a2670 100644 --- a/src/server/GoProController.h +++ b/src/server/GoProController.h @@ -330,6 +330,7 @@ class GoProController { /// - target /// std::string getFetchURL(std::string target_ip, bool is_local); + std::string getThumbnailData(std::string target_ip, std::string path); #pragma endregion #pragma endregion diff --git a/src/server/controller/media.cpp b/src/server/controller/media.cpp index 0e705bc3..cee1c4d2 100644 --- a/src/server/controller/media.cpp +++ b/src/server/controller/media.cpp @@ -159,4 +159,8 @@ std::string GoProController::getFetchURL(std::string target_ip, bool is_local){ std::cerr << ex.what() << std::endl; return ""; } -} \ No newline at end of file +} + +std::string GoProController::getThumbnailData(std::string target_ip, std::string path){ + +} diff --git a/src/server/main.cpp b/src/server/main.cpp index e68bc1e9..f652d8b3 100644 --- a/src/server/main.cpp +++ b/src/server/main.cpp @@ -336,6 +336,7 @@ void MediaAction(const WebSocketChannelPtr& channel, json j){ std::string target = ""; std::string name = ""; std::string item = ""; + std::string path = ""; std::string ip = ""; std::string dir = ""; std::string filename = ""; @@ -351,6 +352,9 @@ void MediaAction(const WebSocketChannelPtr& channel, json j){ if(j["item"].is_string()){ item = j["item"].get(); } + if(j["path"].is_string()){ + path = j["path"].get(); + } if(j["ip"].is_string()){ ip = j["ip"].get(); } @@ -373,8 +377,7 @@ void MediaAction(const WebSocketChannelPtr& channel, json j){ r["data"] = json::array(); } channel->send(getPacket("media:lastmedia", r)); - } - else if(name == "url"){ + }else if(name == "url"){ // Download the media one at the time... thanks std::lock_guard lock(download_mtx); r["local"] = local; @@ -383,7 +386,11 @@ void MediaAction(const WebSocketChannelPtr& channel, json j){ r["filename"] = filename; r["path"] = controller.getFetchURL(ip, local); channel->send(getPacket("media:url", r)); - }else{ + }else if(name == "thumbnail"){ + r["data"] = controller.getThumbnailData(ip, path); + channel->send(getPacket("media:thumbnail", r)); + } + else{ channel->send(getPacket("media:unknown", r)); } } From 8675227cbe72cd3b4f8ee74b165097ae102175fa Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Tue, 5 May 2026 16:15:09 +0800 Subject: [PATCH 40/64] Added base64 encoder function in server side --- src/common/iphelper.h | 25 +++++++++++++++++++++++++ src/server/GoProController.h | 5 +++-- src/server/controller/media.cpp | 19 +++++++++++++++++-- src/server/main.cpp | 3 ++- src/server/private/private.cpp | 15 +++++++++++++++ 5 files changed, 62 insertions(+), 5 deletions(-) diff --git a/src/common/iphelper.h b/src/common/iphelper.h index 0414cc4c..0ec1aeaa 100644 --- a/src/common/iphelper.h +++ b/src/common/iphelper.h @@ -206,6 +206,11 @@ inline size_t write_callback_pure(void* contents, size_t size, size_t nmemb, std return size * nmemb; } +inline size_t write_callback_char(void* contents, size_t size, size_t nmemb, std::vector* userp) { + userp->insert(userp->end(), static_cast(contents), static_cast(contents) + size * nmemb); + return size * nmemb; +} + inline std::string GetRemoteIPBySerial(std::string serial){ if(serial.size() < 3){ std::cerr << "Serial string must be at least 3" << "\n"; @@ -257,6 +262,26 @@ inline std::string exec(std::string cmd, int64_t timeout = 1500L, int64_t connec return result; } +inline std::vector exec_byte(std::string cmd, int64_t timeout = 1500L, int64_t connection_timeout = 1000L){ + CURL* curl = curl_easy_init(); + std::vector result = std::vector(); + + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, cmd.c_str()); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback_char); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &result); + curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, timeout); + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, connection_timeout); + CURLcode res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + }else{ + std::cerr << "[Error] iphelper.h, Curl init failed" << std::endl; + } + + return std::move(result); +} + inline std::vector execs(std::vector cmds) { CURLM* curlm = curl_multi_init(); CURL* curl = NULL; diff --git a/src/server/GoProController.h b/src/server/GoProController.h index 197a2670..ddf4ddb6 100644 --- a/src/server/GoProController.h +++ b/src/server/GoProController.h @@ -330,7 +330,7 @@ class GoProController { /// - target /// std::string getFetchURL(std::string target_ip, bool is_local); - std::string getThumbnailData(std::string target_ip, std::string path); + std::string getThumbnailData(std::string target_ip, std::string path, bool is_local); #pragma endregion #pragma endregion @@ -406,7 +406,8 @@ class GoProController { // Utility calls SingleResponse _getSingleResponse(std::string target, std::string suffix); std::vector _getAllResponse(std::vector targets, std::string suffix); - + std::string base64_encode(const std::vector& data); + int32_t _get_current_model(json hwinfo); #pragma endregion diff --git a/src/server/controller/media.cpp b/src/server/controller/media.cpp index cee1c4d2..32fdcec4 100644 --- a/src/server/controller/media.cpp +++ b/src/server/controller/media.cpp @@ -161,6 +161,21 @@ std::string GoProController::getFetchURL(std::string target_ip, bool is_local){ } } -std::string GoProController::getThumbnailData(std::string target_ip, std::string path){ - +std::string GoProController::getThumbnailData(std::string target_ip, std::string path, bool is_local){ + std::cout << "Http GET /last_media " << target_ip << ", " << is_local << std::endl; + + if (target_ip.empty()) { + std::cerr << "[last_media] " << target_ip << " Missing ip parameter" << std::endl; + return ""; + } + + try{ + const std::vector res = exec_byte("http://" + target_ip + ":8080/gopro/media/screennail?path=" + path); + std::string result = base64_encode(res); + return result; + } + catch(const std::exception& ex){ + std::cerr << ex.what() << std::endl; + return ""; + } } diff --git a/src/server/main.cpp b/src/server/main.cpp index f652d8b3..d1bf9385 100644 --- a/src/server/main.cpp +++ b/src/server/main.cpp @@ -387,7 +387,8 @@ void MediaAction(const WebSocketChannelPtr& channel, json j){ r["path"] = controller.getFetchURL(ip, local); channel->send(getPacket("media:url", r)); }else if(name == "thumbnail"){ - r["data"] = controller.getThumbnailData(ip, path); + r["local"] = local; + r["data"] = controller.getThumbnailData(ip, path, local); channel->send(getPacket("media:thumbnail", r)); } else{ diff --git a/src/server/private/private.cpp b/src/server/private/private.cpp index b926be28..441b590b 100644 --- a/src/server/private/private.cpp +++ b/src/server/private/private.cpp @@ -85,3 +85,18 @@ std::vector GoProController::_getAllResponse(std::vector& data) { + std::string out; + int val = 0, valb = -6; + for (u_char c : data) { + val = (val << 8) + c; + valb += 8; + while (valb >= 0) { + out.push_back(base64_chars[(val >> valb) & 0x3F]); + valb -= 6; + } + } + if (valb > -6) out.push_back(base64_chars[((val << 8) >> (valb + 8)) & 0x3F]); + while (out.size() % 4) out.push_back('='); + return out; +} From 7200bd8e2fb61a890a31cd5b8a7351aa27ee4d18 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Tue, 5 May 2026 16:27:37 +0800 Subject: [PATCH 41/64] Added media list fetch --- src/master/GoProMaster.cpp | 23 +++++++++++++++++++++++ src/master/GoProMaster.h | 1 + src/server/main.cpp | 9 +++++++++ 3 files changed, 33 insertions(+) diff --git a/src/master/GoProMaster.cpp b/src/master/GoProMaster.cpp index 5fcb0de2..4ab1d811 100644 --- a/src/master/GoProMaster.cpp +++ b/src/master/GoProMaster.cpp @@ -1083,3 +1083,26 @@ int32_t GoProMaster::findCamera(const std::string server, const std::string ip){ } return -1; } + +std::vector GoProMaster::decodeBase64(const std::string& input) { + static const std::string base64_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + + std::vector T(256, -1); + for (int32_t i = 0; i < 64; i++) T[base64_chars[i]] = i; + + std::vector out; + int32_t val = 0, valb = -8; + for (u_char c : input) { + if (T[c] == -1) continue; // Skip non-base64 characters + val = (val << 6) + T[c]; + valb += 6; + if (valb >= 0) { + out.push_back(static_cast((val >> valb) & 0xFF)); + valb -= 8; + } + } + return out; +} diff --git a/src/master/GoProMaster.h b/src/master/GoProMaster.h index bb14297a..1953d13b 100644 --- a/src/master/GoProMaster.h +++ b/src/master/GoProMaster.h @@ -234,4 +234,5 @@ class GoProMaster { size_t getServerCount(); int32_t findServer(const std::string ip); int32_t findCamera(const std::string server, const std::string ip); + std::vector decodeBase64(const std::string& input); }; diff --git a/src/server/main.cpp b/src/server/main.cpp index d1bf9385..4bd3193f 100644 --- a/src/server/main.cpp +++ b/src/server/main.cpp @@ -386,6 +386,15 @@ void MediaAction(const WebSocketChannelPtr& channel, json j){ r["filename"] = filename; r["path"] = controller.getFetchURL(ip, local); channel->send(getPacket("media:url", r)); + }else if(name == "list"){ + resultText = controller.getMediaList(target); + if(json::accept(resultText)){ + r["data"] = json::parse(resultText); + }else{ + r["data"] = json::array(); + } + channel->send(getPacket("media:list", r)); + }else if(name == "thumbnail"){ r["local"] = local; r["data"] = controller.getThumbnailData(ip, path, local); From e0618336ec3d8cf2a84009ae4e7a7946fa38b72b Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Thu, 7 May 2026 09:58:29 +0800 Subject: [PATCH 42/64] Added media info query method for server --- src/master/popup/media_browser_popwin.cpp | 25 +++++++++++++++++++++-- src/master/popup/media_browser_popwin.h | 11 ++++++++++ src/master/windows/inspector.h | 4 ++-- src/server/GoProController.h | 1 + src/server/controller/media.cpp | 22 ++++++++++++++++++-- src/server/main.cpp | 10 +++++---- 6 files changed, 63 insertions(+), 10 deletions(-) diff --git a/src/master/popup/media_browser_popwin.cpp b/src/master/popup/media_browser_popwin.cpp index ea919210..8a072b95 100644 --- a/src/master/popup/media_browser_popwin.cpp +++ b/src/master/popup/media_browser_popwin.cpp @@ -34,12 +34,12 @@ void MediaBrowserPopup::render(){ int32_t s = master->findCamera(state->current_camera_server, state->current_camera_item); if(s >= 0) { const CameraInfo ci = master->getCamera_Clone(s); - ImGui::BeginChild("Body##Media_Browser_ChildWin_Body", ImVec2(unit.x * 10.0F - style.ItemSpacing.x, unit.y * 7.5F)); + ImGui::BeginChild("Body##Media_Browser_ChildWin_Body", ImVec2(unit.x * 10.0F - (style.ItemSpacing.x * 2), unit.y * 7.5F)); { draw_body(ci); } ImGui::EndChild(); - ImGui::BeginChild("Header##Media_Browser_ChildWin_Header", ImVec2(unit.x * 10.0F - style.ItemSpacing.x, unit.y * 1.6F)); + ImGui::BeginChild("Header##Media_Browser_ChildWin_Header", ImVec2(unit.x * 10.0F - (style.ItemSpacing.x * 2), unit.y * 1.6F)); { draw_header(ci); } @@ -52,6 +52,27 @@ void MediaBrowserPopup::render(){ void MediaBrowserPopup::draw_header(const CameraInfo& c){ bool is_enable = c.ip.size() > 0; + if(ImGui::Button("Cancel")){ + + } + ImGui::BeginDisabled(!is_enable); + ImGui::SameLine(); + if(ImGui::Button("Download")){ + + } + ImGui::SameLine(); + if(ImGui::Button("Download To")){ + + } + ImGui::SameLine(); + if(ImGui::Button("Delete")){ + + } + ImGui::SameLine(); + if(ImGui::Button("Delete All")){ + + } + ImGui::EndDisabled(); } void MediaBrowserPopup::draw_body(const CameraInfo& c){ diff --git a/src/master/popup/media_browser_popwin.h b/src/master/popup/media_browser_popwin.h index 766191a5..fdbcfb76 100644 --- a/src/master/popup/media_browser_popwin.h +++ b/src/master/popup/media_browser_popwin.h @@ -1,6 +1,13 @@ #pragma once #include "base_pop_window.h" +struct MediaInfo { + std::string filename; + uint32_t created; + uint32_t modified; + size_t size; +}; + class MediaBrowserPopup : public BasePopWindow { public: MediaBrowserPopup( @@ -14,4 +21,8 @@ class MediaBrowserPopup : public BasePopWindow { protected: virtual void draw_header(const CameraInfo& c); virtual void draw_body(const CameraInfo& c); + + virtual void draw_item(const ) +private: + int32_t selected = -1; }; \ No newline at end of file diff --git a/src/master/windows/inspector.h b/src/master/windows/inspector.h index 03ec0a13..b5d01807 100644 --- a/src/master/windows/inspector.h +++ b/src/master/windows/inspector.h @@ -71,6 +71,6 @@ class InspectorWindow : public BaseWindow { /// 1: Front Characters /// 2: Back Characters /// - int32_t media_name_rule_type; - int32_t media_name_character_count; + int32_t media_name_rule_type = 0; + int32_t media_name_character_count = 0; }; diff --git a/src/server/GoProController.h b/src/server/GoProController.h index ddf4ddb6..aaef29ed 100644 --- a/src/server/GoProController.h +++ b/src/server/GoProController.h @@ -331,6 +331,7 @@ class GoProController { /// std::string getFetchURL(std::string target_ip, bool is_local); std::string getThumbnailData(std::string target_ip, std::string path, bool is_local); + std::string getMediaInfoData(std::string target_ip, std::string path, bool is_local); #pragma endregion #pragma endregion diff --git a/src/server/controller/media.cpp b/src/server/controller/media.cpp index 32fdcec4..52f62d11 100644 --- a/src/server/controller/media.cpp +++ b/src/server/controller/media.cpp @@ -162,10 +162,10 @@ std::string GoProController::getFetchURL(std::string target_ip, bool is_local){ } std::string GoProController::getThumbnailData(std::string target_ip, std::string path, bool is_local){ - std::cout << "Http GET /last_media " << target_ip << ", " << is_local << std::endl; + std::cout << "Http GET /thumbnail " << target_ip << ", " << is_local << std::endl; if (target_ip.empty()) { - std::cerr << "[last_media] " << target_ip << " Missing ip parameter" << std::endl; + std::cerr << "[thumbnail] " << target_ip << " Missing ip parameter" << std::endl; return ""; } @@ -179,3 +179,21 @@ std::string GoProController::getThumbnailData(std::string target_ip, std::string return ""; } } + +std::string GoProController::getMediaInfoData(std::string target_ip, std::string path, bool is_local){ + std::cout << "Http GET /media_info " << target_ip << ", " << is_local << std::endl; + + if (target_ip.empty()) { + std::cerr << "[media_info] " << target_ip << " Missing ip parameter" << std::endl; + return ""; + } + + try{ + std::string result = exec("http://" + target_ip + ":8080/gopro/media/info?path=" + path); + return result; + } + catch(const std::exception& ex){ + std::cerr << ex.what() << std::endl; + return ""; + } +} diff --git a/src/server/main.cpp b/src/server/main.cpp index 4bd3193f..b9a60adb 100644 --- a/src/server/main.cpp +++ b/src/server/main.cpp @@ -393,14 +393,16 @@ void MediaAction(const WebSocketChannelPtr& channel, json j){ }else{ r["data"] = json::array(); } - channel->send(getPacket("media:list", r)); - + channel->send(getPacket("media:list", wr)); }else if(name == "thumbnail"){ r["local"] = local; r["data"] = controller.getThumbnailData(ip, path, local); channel->send(getPacket("media:thumbnail", r)); - } - else{ + }else if(name == "info"){ + r["local"] = local; + r["data"] = controller.getMediaInfoData(ip, path, local); + channel->send(getPacket("media:info", r)); + }else{ channel->send(getPacket("media:unknown", r)); } } From 63d7b7fca526299412a8a122e839a567965cfe42 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Thu, 7 May 2026 10:10:18 +0800 Subject: [PATCH 43/64] Update state structure --- src/master/data/state.h | 8 ++++++++ src/master/popup/media_browser_popwin.cpp | 4 ++++ src/master/popup/media_browser_popwin.h | 9 +-------- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/master/data/state.h b/src/master/data/state.h index cf8db3b6..99dfa142 100644 --- a/src/master/data/state.h +++ b/src/master/data/state.h @@ -17,6 +17,13 @@ enum class InspectorObjectType { Camera }; +struct MediaInfo { + std::string filename; + uint32_t created; + uint32_t modified; + size_t size; +}; + struct GlobalState { bool done; int32_t applying_all_count = 0; @@ -29,6 +36,7 @@ struct GlobalState { // Current select camera setting std::string current_camera_name = ""; std::string current_download_location = ""; + std::vector current_media_list = std::vector(); json current_setting_items; bool current_setting_items_bind = false; json current_status_items; diff --git a/src/master/popup/media_browser_popwin.cpp b/src/master/popup/media_browser_popwin.cpp index 8a072b95..54126394 100644 --- a/src/master/popup/media_browser_popwin.cpp +++ b/src/master/popup/media_browser_popwin.cpp @@ -77,4 +77,8 @@ void MediaBrowserPopup::draw_header(const CameraInfo& c){ void MediaBrowserPopup::draw_body(const CameraInfo& c){ if(c.ip.size() == 0) return; +} + +bool MediaBrowserPopup::draw_item(const MediaInfo& mi){ + return false; } \ No newline at end of file diff --git a/src/master/popup/media_browser_popwin.h b/src/master/popup/media_browser_popwin.h index fdbcfb76..c547d7e4 100644 --- a/src/master/popup/media_browser_popwin.h +++ b/src/master/popup/media_browser_popwin.h @@ -1,13 +1,6 @@ #pragma once #include "base_pop_window.h" -struct MediaInfo { - std::string filename; - uint32_t created; - uint32_t modified; - size_t size; -}; - class MediaBrowserPopup : public BasePopWindow { public: MediaBrowserPopup( @@ -22,7 +15,7 @@ class MediaBrowserPopup : public BasePopWindow { virtual void draw_header(const CameraInfo& c); virtual void draw_body(const CameraInfo& c); - virtual void draw_item(const ) + virtual bool draw_item(const MediaInfo& mi); private: int32_t selected = -1; }; \ No newline at end of file From 9abb81e2786e06f96175a480c55cce85f2e9c956 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Thu, 7 May 2026 10:11:39 +0800 Subject: [PATCH 44/64] Added master function for media --- src/master/GoProMaster.cpp | 8 ++++++++ src/master/GoProMaster.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/src/master/GoProMaster.cpp b/src/master/GoProMaster.cpp index 4ab1d811..5ef2d6f7 100644 --- a/src/master/GoProMaster.cpp +++ b/src/master/GoProMaster.cpp @@ -347,6 +347,14 @@ void GoProMaster::download_last_media(const std::string ip, const DownloadMediaP }).detach(); } +void GoProMaster::get_media_info(const std::string ip, const std::string path){ + +} + +void GoProMaster::get_media_list(const std::string ip){ + +} + void GoProMaster::presetSwitch(const std::string server, const std::string target, int32_t mode) { std::thread([=](){ for (auto& s : servers) { diff --git a/src/master/GoProMaster.h b/src/master/GoProMaster.h index 1953d13b..1070ab44 100644 --- a/src/master/GoProMaster.h +++ b/src/master/GoProMaster.h @@ -96,6 +96,8 @@ class GoProMaster { void preview_end(std::string server, std::string target); void media_only(const std::string command, std::string target = ""); void download_last_media(const std::string ip, const DownloadMediaParameters params); + void get_media_info(const std::string ip, const std::string path); + void get_media_list(const std::string ip); void presetSwitch(const std::string server, const std::string target, int32_t mode); void locate(const std::string server, const std::string target); From 36b8365617dcdb34145d0cb0d92ddaf1e6f3fb15 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Thu, 7 May 2026 13:40:39 +0800 Subject: [PATCH 45/64] Added master send media info and list command to server --- src/master/GoProMaster.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/master/GoProMaster.cpp b/src/master/GoProMaster.cpp index 5ef2d6f7..f4c50451 100644 --- a/src/master/GoProMaster.cpp +++ b/src/master/GoProMaster.cpp @@ -348,11 +348,38 @@ void GoProMaster::download_last_media(const std::string ip, const DownloadMediaP } void GoProMaster::get_media_info(const std::string ip, const std::string path){ + json data = json::object(); + data["key"] = "media"; + data["value"] = json::object(); + data["value"]["name"] = "info"; + data["value"]["path"] = path; + data["value"]["target"] = ip; + for(auto s : servers){ + bool islocal = s->server == "127.0.0.1"; + data["value"]["local"] = islocal; + if((s->ip == server || server.size() == 0) && s->connected){ + s->client->send(data.dump()); + break; + } + } } void GoProMaster::get_media_list(const std::string ip){ + json data = json::object(); + data["key"] = "media"; + data["value"] = json::object(); + data["value"]["name"] = "list"; + data["value"]["target"] = ip; + for(auto s : servers){ + bool islocal = s->server == "127.0.0.1"; + data["value"]["local"] = islocal; + if((s->ip == server || server.size() == 0) && s->connected){ + s->client->send(data.dump()); + break; + } + } } void GoProMaster::presetSwitch(const std::string server, const std::string target, int32_t mode) { From 68fef3098420b87c6a6f57baa9a2f8a5070e115b Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Thu, 7 May 2026 14:31:59 +0800 Subject: [PATCH 46/64] Register media list update event --- src/master/GoProMaster.cpp | 66 ++++++++++++++++++++++++++++++++++++++ src/master/GoProMaster.h | 3 ++ src/master/data/state.h | 2 ++ src/master/main.cpp | 6 ++++ 4 files changed, 77 insertions(+) diff --git a/src/master/GoProMaster.cpp b/src/master/GoProMaster.cpp index f4c50451..10d428f4 100644 --- a/src/master/GoProMaster.cpp +++ b/src/master/GoProMaster.cpp @@ -470,6 +470,10 @@ bool GoProMaster::directoryExists(const std::string& path) { return false; } +void GoProMaster::registerCameraMediaListFeedback(camera_media_list_feedback v){ + _camera_media_list_feedback = v; +} + void GoProMaster::registerCameraSettingFeedback(camera_setting_feedback v){ _camera_setting_feedback = v; } @@ -932,6 +936,68 @@ void GoProMaster::processMessage(const std::string& server, const std::string& m } } } + else if(key == "media:info"){ + + } + else if(key == "media:list"){ + std::vector media_list = std::vector(); + if(!data["value"]["data"].is_array()){ + std::cerr << "Invalid message from " << server << ": " << msg << std::endl; + std::cerr << "media:list, return value should be array" << std::endl; + return; + } + + for(auto ip = data["value"]["data"].begin(); ip != data["value"]["data"].end(); ++ip){ + std::string source = ""; + if(ip.value()["ip"].is_string()){ + source = ip.value()["ip"].get(); + } else continue; + if(ip.value()["status"].is_object()){ + if(ip.value()["status"]["media"].is_array()){ + json mediaarr = ip.value()["status"]["media"]; + for(auto ip2 = mediaarr.begin(); ip2 != mediaarr.end(); ++ip2){ + std::string d = ""; + if(ip2["d"].is_string()){ + d = ip2["d"].get(); + } else continue; + if(ip2["fs"].is_array()){ + json fsarr = ip2["fs"]; + for(auto ip3 = fsarr.begin(); ip3 != fsarr.end(); ++ip3){ + MediaInfo info = MediaInfo(); + if(ip3["n"].is_string()){ + info.filename = d; + info.filename += "/"; + info.filename += ip3["n"].get(); + } else continue; + if(ip3["s"].is_number()){ + info.size = ip3["s"].get(); + } + if(ip3["cre"].is_number()){ + info.created = ip3["cre"].get(); + } + if(ip3["mod"].is_number()){ + info.modified = ip3["mod"].get(); + } + media_list.push_back(info); + } + } + } + } + } + } + + if(_camera_media_list_feedback != NULL) + _camera_media_list_feedback(media_list); + } + else if(key == "thumbnail"){ + if(!data["value"]["data"].is_string()){ + std::cerr << "Invalid message from " << server << ": " << msg << std::endl; + std::cerr << "media:thumbnail, return value should be string" << std::endl; + return; + } + + std::vector raw_data = decodeBase64(data["value"]["data"].get()); + } else{ std::cerr << "Invalid message from " << server << ": " << msg << std::endl; std::cerr << "No registerd action from this key: " << key << std::endl; diff --git a/src/master/GoProMaster.h b/src/master/GoProMaster.h index 1070ab44..c6122465 100644 --- a/src/master/GoProMaster.h +++ b/src/master/GoProMaster.h @@ -17,6 +17,7 @@ #include "data/camera_info.h" #include "data/server_connection.h" +typedef void (*camera_media_list_feedback)(std::vector media_list); typedef void (*camera_setting_feedback)(std::string ip, json setting); typedef void (*camera_status_feedback)(std::string ip, json status); typedef void (*camera_hw_feedback)(std::string ip, json hw); @@ -108,6 +109,7 @@ class GoProMaster { bool directoryExists(const std::string& path); + void registerCameraMediaListFeedback(camera_media_list_feedback v); /// /// Register the feedback event /// Called when fetch inspector setting data @@ -185,6 +187,7 @@ class GoProMaster { */ std::unordered_map stateQueryFinish = std::unordered_map(); std::unordered_map mediaQueryFinish = std::unordered_map(); + camera_media_list_feedback _camera_media_list_feedback = NULL; camera_setting_feedback _camera_setting_feedback = NULL; camera_status_feedback _camera_status_feedback = NULL; camera_hw_feedback _camera_hw_feedback = NULL; diff --git a/src/master/data/state.h b/src/master/data/state.h index 99dfa142..8c43ed20 100644 --- a/src/master/data/state.h +++ b/src/master/data/state.h @@ -6,6 +6,7 @@ */ #pragma once #include +#include #include using json = nlohmann::json; @@ -36,6 +37,7 @@ struct GlobalState { // Current select camera setting std::string current_camera_name = ""; std::string current_download_location = ""; + std::mutex media_list_mtx; std::vector current_media_list = std::vector(); json current_setting_items; bool current_setting_items_bind = false; diff --git a/src/master/main.cpp b/src/master/main.cpp index e3166189..360e90f8 100644 --- a/src/master/main.cpp +++ b/src/master/main.cpp @@ -129,6 +129,11 @@ void applyAllFeedback(){ } } +void updateMediaList(std::vector data){ + std::lock_guard lock(global_state->media_list_mtx); + global_state->current_media_list = data; +} + void updateServerList(){ std::cout << "updateServerList" << std::endl; json data = json::object(); @@ -202,6 +207,7 @@ int main(int, char**) WIN_INIT(preset_manager_popwin, PresetManagerPopup, pop_windows_array, 5); WIN_INIT(media_browser_popwin, MediaBrowserPopup, pop_windows_array, 6); // Register event for master + master->registerCameraMediaListFeedback(updateMediaList); master->registerCameraSettingFeedback(settingGetterFeedback); master->registerCameraStatusFeedback(statusGetterFeedback); master->registerCameraHWFeedback(hwGetterFeedback); From c375e0c6a2786c4978292cacbcbf3d7e75146a36 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Thu, 7 May 2026 14:58:15 +0800 Subject: [PATCH 47/64] Successfully create media list in master server --- src/master/GoProMaster.cpp | 36 ++++++++++++----------- src/master/GoProMaster.h | 5 ++-- src/master/popup/media_browser_popwin.cpp | 14 ++++++++- src/master/popup/media_browser_popwin.h | 2 +- src/server/main.cpp | 2 +- src/server/private/private.cpp | 5 ++++ 6 files changed, 42 insertions(+), 22 deletions(-) diff --git a/src/master/GoProMaster.cpp b/src/master/GoProMaster.cpp index 10d428f4..b1e72ab6 100644 --- a/src/master/GoProMaster.cpp +++ b/src/master/GoProMaster.cpp @@ -347,7 +347,7 @@ void GoProMaster::download_last_media(const std::string ip, const DownloadMediaP }).detach(); } -void GoProMaster::get_media_info(const std::string ip, const std::string path){ +void GoProMaster::get_media_info(const std::string server, const std::string ip, const std::string path){ json data = json::object(); data["key"] = "media"; data["value"] = json::object(); @@ -356,7 +356,8 @@ void GoProMaster::get_media_info(const std::string ip, const std::string path){ data["value"]["target"] = ip; for(auto s : servers){ - bool islocal = s->server == "127.0.0.1"; + if(s->ip != server) continue; + bool islocal = s->ip == "127.0.0.1"; data["value"]["local"] = islocal; if((s->ip == server || server.size() == 0) && s->connected){ s->client->send(data.dump()); @@ -365,7 +366,7 @@ void GoProMaster::get_media_info(const std::string ip, const std::string path){ } } -void GoProMaster::get_media_list(const std::string ip){ +void GoProMaster::get_media_list(const std::string server, const std::string ip){ json data = json::object(); data["key"] = "media"; data["value"] = json::object(); @@ -373,7 +374,8 @@ void GoProMaster::get_media_list(const std::string ip){ data["value"]["target"] = ip; for(auto s : servers){ - bool islocal = s->server == "127.0.0.1"; + if(s->ip != server) continue; + bool islocal = s->ip == "127.0.0.1"; data["value"]["local"] = islocal; if((s->ip == server || server.size() == 0) && s->connected){ s->client->send(data.dump()); @@ -954,29 +956,29 @@ void GoProMaster::processMessage(const std::string& server, const std::string& m } else continue; if(ip.value()["status"].is_object()){ if(ip.value()["status"]["media"].is_array()){ - json mediaarr = ip.value()["status"]["media"]; + auto mediaarr = ip.value()["status"]["media"]; for(auto ip2 = mediaarr.begin(); ip2 != mediaarr.end(); ++ip2){ std::string d = ""; - if(ip2["d"].is_string()){ - d = ip2["d"].get(); + if(ip2.value()["d"].is_string()){ + d = ip2.value()["d"].get(); } else continue; - if(ip2["fs"].is_array()){ - json fsarr = ip2["fs"]; + if(ip2.value()["fs"].is_array()){ + auto fsarr = ip2.value()["fs"]; for(auto ip3 = fsarr.begin(); ip3 != fsarr.end(); ++ip3){ MediaInfo info = MediaInfo(); - if(ip3["n"].is_string()){ + if(ip3.value()["n"].is_string()){ info.filename = d; info.filename += "/"; - info.filename += ip3["n"].get(); + info.filename += ip3.value()["n"].get(); } else continue; - if(ip3["s"].is_number()){ - info.size = ip3["s"].get(); + if(ip3.value()["s"].is_number()){ + info.size = ip3.value()["s"].get(); } - if(ip3["cre"].is_number()){ - info.created = ip3["cre"].get(); + if(ip3.value()["cre"].is_number()){ + info.created = ip3.value()["cre"].get(); } - if(ip3["mod"].is_number()){ - info.modified = ip3["mod"].get(); + if(ip3.value()["mod"].is_number()){ + info.modified = ip3.value()["mod"].get(); } media_list.push_back(info); } diff --git a/src/master/GoProMaster.h b/src/master/GoProMaster.h index c6122465..d29d723f 100644 --- a/src/master/GoProMaster.h +++ b/src/master/GoProMaster.h @@ -14,6 +14,7 @@ #include #include "../common/iphelper.h" #include "../common/camera_code.h" +#include "data/state.h" #include "data/camera_info.h" #include "data/server_connection.h" @@ -97,8 +98,8 @@ class GoProMaster { void preview_end(std::string server, std::string target); void media_only(const std::string command, std::string target = ""); void download_last_media(const std::string ip, const DownloadMediaParameters params); - void get_media_info(const std::string ip, const std::string path); - void get_media_list(const std::string ip); + void get_media_info(const std::string server, const std::string ip, const std::string path); + void get_media_list(const std::string server, const std::string ip); void presetSwitch(const std::string server, const std::string target, int32_t mode); void locate(const std::string server, const std::string target); diff --git a/src/master/popup/media_browser_popwin.cpp b/src/master/popup/media_browser_popwin.cpp index 54126394..ae1b37a5 100644 --- a/src/master/popup/media_browser_popwin.cpp +++ b/src/master/popup/media_browser_popwin.cpp @@ -14,6 +14,12 @@ MediaBrowserPopup::~MediaBrowserPopup(){ } +void MediaBrowserPopup::trigger(bool value){ + BasePopWindow::trigger(value); + if(value){ + master->get_media_list(state->current_camera_server, state->current_camera_item); + } +} void MediaBrowserPopup::render(){ ImGuiIO& io = ImGui::GetIO(); @@ -53,7 +59,7 @@ void MediaBrowserPopup::render(){ void MediaBrowserPopup::draw_header(const CameraInfo& c){ bool is_enable = c.ip.size() > 0; if(ImGui::Button("Cancel")){ - + trigger(false); } ImGui::BeginDisabled(!is_enable); ImGui::SameLine(); @@ -77,6 +83,12 @@ void MediaBrowserPopup::draw_header(const CameraInfo& c){ void MediaBrowserPopup::draw_body(const CameraInfo& c){ if(c.ip.size() == 0) return; + std::lock_guard lock(state->media_list_mtx); + std::vector media_list = state->current_media_list; + for(int i = 0; i < media_list.size(); i++){ + const MediaInfo& mi = media_list.at(i); + ImGui::Text("%s", mi.filename.c_str()); + } } bool MediaBrowserPopup::draw_item(const MediaInfo& mi){ diff --git a/src/master/popup/media_browser_popwin.h b/src/master/popup/media_browser_popwin.h index c547d7e4..223b62ed 100644 --- a/src/master/popup/media_browser_popwin.h +++ b/src/master/popup/media_browser_popwin.h @@ -9,7 +9,7 @@ class MediaBrowserPopup : public BasePopWindow { std::shared_ptr _master); ~MediaBrowserPopup(); - //virtual void trigger(bool value) override; + virtual void trigger(bool value) override; virtual void render() override; protected: virtual void draw_header(const CameraInfo& c); diff --git a/src/server/main.cpp b/src/server/main.cpp index b9a60adb..e2fcc802 100644 --- a/src/server/main.cpp +++ b/src/server/main.cpp @@ -393,7 +393,7 @@ void MediaAction(const WebSocketChannelPtr& channel, json j){ }else{ r["data"] = json::array(); } - channel->send(getPacket("media:list", wr)); + channel->send(getPacket("media:list", r)); }else if(name == "thumbnail"){ r["local"] = local; r["data"] = controller.getThumbnailData(ip, path, local); diff --git a/src/server/private/private.cpp b/src/server/private/private.cpp index 441b590b..d6b8c8f2 100644 --- a/src/server/private/private.cpp +++ b/src/server/private/private.cpp @@ -86,6 +86,11 @@ std::vector GoProController::_getAllResponse(std::vector& data) { + static const std::string base64_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + std::string out; int val = 0, valb = -6; for (u_char c : data) { From b70027fb6630a35d6164d2a6f539bc519bd22653 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Thu, 7 May 2026 15:00:07 +0800 Subject: [PATCH 48/64] Help selection for meida browser --- src/master/popup/media_browser_popwin.cpp | 6 ++++-- src/master/popup/media_browser_popwin.h | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/master/popup/media_browser_popwin.cpp b/src/master/popup/media_browser_popwin.cpp index ae1b37a5..ee18c933 100644 --- a/src/master/popup/media_browser_popwin.cpp +++ b/src/master/popup/media_browser_popwin.cpp @@ -87,10 +87,12 @@ void MediaBrowserPopup::draw_body(const CameraInfo& c){ std::vector media_list = state->current_media_list; for(int i = 0; i < media_list.size(); i++){ const MediaInfo& mi = media_list.at(i); - ImGui::Text("%s", mi.filename.c_str()); + if(draw_item(mi)){ + selected = mi.filename; + } } } bool MediaBrowserPopup::draw_item(const MediaInfo& mi){ - return false; + return ImGui::Selectable(mi.filename.c_str(), selected == mi.filename); } \ No newline at end of file diff --git a/src/master/popup/media_browser_popwin.h b/src/master/popup/media_browser_popwin.h index 223b62ed..f7a3de3f 100644 --- a/src/master/popup/media_browser_popwin.h +++ b/src/master/popup/media_browser_popwin.h @@ -17,5 +17,5 @@ class MediaBrowserPopup : public BasePopWindow { virtual bool draw_item(const MediaInfo& mi); private: - int32_t selected = -1; + std::string selected = ""; }; \ No newline at end of file From 344a55a8014022a616061de778b2a52c81ca7d66 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Thu, 7 May 2026 15:01:13 +0800 Subject: [PATCH 49/64] Update media browser layout --- src/master/popup/media_browser_popwin.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/master/popup/media_browser_popwin.cpp b/src/master/popup/media_browser_popwin.cpp index ee18c933..4c965dcf 100644 --- a/src/master/popup/media_browser_popwin.cpp +++ b/src/master/popup/media_browser_popwin.cpp @@ -58,6 +58,10 @@ void MediaBrowserPopup::render(){ void MediaBrowserPopup::draw_header(const CameraInfo& c){ bool is_enable = c.ip.size() > 0; + ImGui::Dummy(ImVec2(10, 10)); + ImGui::Dummy(ImVec2(10, 10)); + ImGui::SameLine(); + if(ImGui::Button("Cancel")){ trigger(false); } From 8b8ee0b7baefc65333f1221cc9a297a5140e3a33 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Thu, 7 May 2026 15:08:01 +0800 Subject: [PATCH 50/64] Added more buttons, For meida browser actions --- src/master/popup/media_browser_popwin.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/master/popup/media_browser_popwin.cpp b/src/master/popup/media_browser_popwin.cpp index 4c965dcf..3df55ecd 100644 --- a/src/master/popup/media_browser_popwin.cpp +++ b/src/master/popup/media_browser_popwin.cpp @@ -61,18 +61,26 @@ void MediaBrowserPopup::draw_header(const CameraInfo& c){ ImGui::Dummy(ImVec2(10, 10)); ImGui::Dummy(ImVec2(10, 10)); ImGui::SameLine(); - + if(ImGui::Button("Cancel")){ trigger(false); } ImGui::BeginDisabled(!is_enable); ImGui::SameLine(); + if(ImGui::Button("Copy URL")){ + + } + ImGui::SameLine(); if(ImGui::Button("Download")){ } ImGui::SameLine(); if(ImGui::Button("Download To")){ + } + ImGui::SameLine(); + if(ImGui::Button("Download All To")){ + } ImGui::SameLine(); if(ImGui::Button("Delete")){ From 6e85ae96ba29fd1247b0df533f2920f41711098a Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Thu, 7 May 2026 17:04:08 +0800 Subject: [PATCH 51/64] Update process message --- src/master/GoProMaster.cpp | 72 ++++++++++++++++++++++- src/master/GoProMaster.h | 2 + src/master/popup/media_browser_popwin.cpp | 64 +++++++++++++++++++- src/master/popup/media_browser_popwin.h | 4 ++ 4 files changed, 138 insertions(+), 4 deletions(-) diff --git a/src/master/GoProMaster.cpp b/src/master/GoProMaster.cpp index b1e72ab6..5f3ed825 100644 --- a/src/master/GoProMaster.cpp +++ b/src/master/GoProMaster.cpp @@ -293,7 +293,77 @@ void GoProMaster::download_last_media(const std::string ip, const DownloadMediaP for(auto& s : cameras){ if(!s->connected) continue; - if(ip.size() > 0 && s->ip != ip) continue; + if(ip.size() == 0 || s->ip != ip) continue; + std::string ext = fs::path(s->last_media).extension().string(); + std::string filename = s->name; + if(filename.size() == 0 || s->name.size() == 0) { + std::cerr << "[download_last_media] filename size is 0, we just skip..." << std::endl; + continue; + } + size_t filename_size = filename.size(); + std::cout << "[download_last_media] \ttype: " << params.type << std::endl; + std::cout << "[download_last_media] \tfilename: " << filename.c_str() << std::endl; + if(params.c_count > 0){ + std::string ccc = ""; + for(int32_t i = 0; i < params.c_count && i < filename_size; i++){ + if(params.type == 1){ + ccc += filename.at(0); + filename.erase(filename.begin()); + } + if(params.type == 2){ + ccc += filename.at(filename.size() - 1); + filename.erase(filename.begin() + filename.size() - 1); + } + } + if(params.type == 2){ + ccc.reserve(); + } + filename = ccc; + } + filename += ext; + bool islocal = s->server == "127.0.0.1"; + + json data = json::object(); + data["key"] = "media"; + data["value"] = json::object(); + data["value"]["name"] = "url"; + data["value"]["item"] = s->name; + data["value"]["ip"] = s->ip; + data["value"]["local"] = islocal; + data["value"]["dir"] = params.dir; + data["value"]["filename"] = filename; + + for(auto ss : servers){ + if(s->server == ss->ip && ss->connected){ + ss->client->send(data.dump()); + downloading_last_media_total++; + break; + } + } + } + if(downloading_last_media_total == 0){ + downloading_last_media_flag = 0; + } + }).detach(); +} + +void GoProMaster::download_all_media(const std::string server, const std::string ip, const std::string folder, std::vector media_list){ + +} + +void GoProMaster::download_single_media(const std::string server, const std::string ip, const std::string folder, MediaInfo media){ + std::thread([=](){ + if(params.put_finish){ + downloading_last_media_flag = 2; + }else{ + downloading_last_media_flag = 1; + } + downloading_last_media_total = 0; + downloading_last_media_done = 0; + + for(auto& s : cameras){ + if(!s->connected) continue; + if(ip.size() == 0 || s->ip != ip || s->server != server) continue; std::string ext = fs::path(s->last_media).extension().string(); std::string filename = s->name; if(filename.size() == 0 || s->name.size() == 0) { diff --git a/src/master/GoProMaster.h b/src/master/GoProMaster.h index d29d723f..6aa636cc 100644 --- a/src/master/GoProMaster.h +++ b/src/master/GoProMaster.h @@ -98,6 +98,8 @@ class GoProMaster { void preview_end(std::string server, std::string target); void media_only(const std::string command, std::string target = ""); void download_last_media(const std::string ip, const DownloadMediaParameters params); + void download_all_media(const std::string server, const std::string ip, const std::string folder, std::vector media_list); + void download_single_media(const std::string server, const std::string ip, const std::string folder, MediaInfo media); void get_media_info(const std::string server, const std::string ip, const std::string path); void get_media_list(const std::string server, const std::string ip); diff --git a/src/master/popup/media_browser_popwin.cpp b/src/master/popup/media_browser_popwin.cpp index 3df55ecd..4c67f855 100644 --- a/src/master/popup/media_browser_popwin.cpp +++ b/src/master/popup/media_browser_popwin.cpp @@ -1,4 +1,5 @@ #include "media_browser_popwin.h" +#include MediaBrowserPopup::MediaBrowserPopup( std::shared_ptr _setting, @@ -17,6 +18,7 @@ MediaBrowserPopup::~MediaBrowserPopup(){ void MediaBrowserPopup::trigger(bool value){ BasePopWindow::trigger(value); if(value){ + selected = ""; master->get_media_list(state->current_camera_server, state->current_camera_item); } } @@ -58,6 +60,7 @@ void MediaBrowserPopup::render(){ void MediaBrowserPopup::draw_header(const CameraInfo& c){ bool is_enable = c.ip.size() > 0; + bool have_select = selected.size() > 0; ImGui::Dummy(ImVec2(10, 10)); ImGui::Dummy(ImVec2(10, 10)); ImGui::SameLine(); @@ -65,32 +68,40 @@ void MediaBrowserPopup::draw_header(const CameraInfo& c){ if(ImGui::Button("Cancel")){ trigger(false); } - ImGui::BeginDisabled(!is_enable); ImGui::SameLine(); + ImGui::BeginDisabled(!have_select); if(ImGui::Button("Copy URL")){ } ImGui::SameLine(); if(ImGui::Button("Download")){ - + } ImGui::SameLine(); if(ImGui::Button("Download To")){ } + ImGui::EndDisabled(); ImGui::SameLine(); if(ImGui::Button("Download All To")){ } ImGui::SameLine(); + ImGui::BeginDisabled(!have_select); if(ImGui::Button("Delete")){ } + ImGui::EndDisabled(); ImGui::SameLine(); if(ImGui::Button("Delete All")){ } - ImGui::EndDisabled(); + + ImGui::Dummy(ImVec2(10, 10)); + + ImGui::Dummy(ImVec2(10, 10)); + ImGui::SameLine(); + ImGui::Text("Camera: %s", c.name.c_str()); } void MediaBrowserPopup::draw_body(const CameraInfo& c){ @@ -107,4 +118,51 @@ void MediaBrowserPopup::draw_body(const CameraInfo& c){ bool MediaBrowserPopup::draw_item(const MediaInfo& mi){ return ImGui::Selectable(mi.filename.c_str(), selected == mi.filename); +} + +void MediaBrowserPopup::open_dialog_for_download_all_folder_selection(){ + SDL_Window* win = SDL_GL_GetCurrentWindow(); + SDL_ShowOpenFolderDialog([](void* userdata, const char* const* filelist, int filter){ + if (!filelist) { + SDL_Log("Error opening file dialog: %s", SDL_GetError()); + } else if (!*filelist) { + SDL_Log("User canceled the dialog."); + } else { + std::string path = ""; + while (*filelist) { + SDL_Log("Selected file: %s", *filelist); + path = *filelist; + filelist++; + } + MediaBrowserPopup* self = static_cast(userdata); + self->download_all_folder_callback(path); + } + }, this, win, NULL, false); +} + +void MediaBrowserPopup::open_dialog_for_download_file_selection(){ + +} + +void MediaBrowserPopup::download_all_folder_callback(const std::string folder){ + int32_t s = master->findCamera(state->current_camera_server, state->current_camera_item); + if(s >= 0) { + const CameraInfo ci = master->getCamera_Clone(s); + master->download_all_media(ci.server, ci.ip, folder, state->current_media_list); + } +} + +void MediaBrowserPopup::download_file_callback(const std::string fullpath){ + int32_t s = master->findCamera(state->current_camera_server, state->current_camera_item); + if(s >= 0) { + const CameraInfo ci = master->getCamera_Clone(s); + + for(int32_t i = 0; i < state->current_media_list.size(); i++){ + const MediaInfo& mi = state->current_media_list.at(i); + if(mi.filename == selected){ + master->download_single_media(ci.server, ci.ip, fullpath, mi); + break; + } + } + } } \ No newline at end of file diff --git a/src/master/popup/media_browser_popwin.h b/src/master/popup/media_browser_popwin.h index f7a3de3f..6c17523c 100644 --- a/src/master/popup/media_browser_popwin.h +++ b/src/master/popup/media_browser_popwin.h @@ -16,6 +16,10 @@ class MediaBrowserPopup : public BasePopWindow { virtual void draw_body(const CameraInfo& c); virtual bool draw_item(const MediaInfo& mi); + virtual void open_dialog_for_download_all_folder_selection(); + virtual void open_dialog_for_download_file_selection(); + virtual void download_all_folder_callback(const std::string folder); + virtual void download_file_callback(const std::string fullpath); private: std::string selected = ""; }; \ No newline at end of file From 373be7afd46a1a6540187044bc465021e18601fa Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Thu, 7 May 2026 17:11:38 +0800 Subject: [PATCH 52/64] Update singled download media file argument list --- src/master/GoProMaster.cpp | 64 +++++++++++++++++++++++++++++++++++++- src/master/GoProMaster.h | 2 +- 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/src/master/GoProMaster.cpp b/src/master/GoProMaster.cpp index 5f3ed825..f3b4ea1a 100644 --- a/src/master/GoProMaster.cpp +++ b/src/master/GoProMaster.cpp @@ -348,10 +348,72 @@ void GoProMaster::download_last_media(const std::string ip, const DownloadMediaP } void GoProMaster::download_all_media(const std::string server, const std::string ip, const std::string folder, std::vector media_list){ + std::thread([=](){ + if(params.put_finish){ + downloading_last_media_flag = 2; + }else{ + downloading_last_media_flag = 1; + } + downloading_last_media_total = 0; + downloading_last_media_done = 0; + + for(auto& s : cameras){ + if(!s->connected) continue; + if(ip.size() == 0 || s->ip != ip || s->server != server) continue; + std::string ext = fs::path(s->last_media).extension().string(); + std::string filename = s->name; + if(filename.size() == 0 || s->name.size() == 0) { + std::cerr << "[download_last_media] filename size is 0, we just skip..." << std::endl; + continue; + } + size_t filename_size = filename.size(); + std::cout << "[download_last_media] \ttype: " << params.type << std::endl; + std::cout << "[download_last_media] \tfilename: " << filename.c_str() << std::endl; + if(params.c_count > 0){ + std::string ccc = ""; + for(int32_t i = 0; i < params.c_count && i < filename_size; i++){ + if(params.type == 1){ + ccc += filename.at(0); + filename.erase(filename.begin()); + } + if(params.type == 2){ + ccc += filename.at(filename.size() - 1); + filename.erase(filename.begin() + filename.size() - 1); + } + } + if(params.type == 2){ + ccc.reserve(); + } + filename = ccc; + } + filename += ext; + bool islocal = s->server == "127.0.0.1"; + json data = json::object(); + data["key"] = "media"; + data["value"] = json::object(); + data["value"]["name"] = "url"; + data["value"]["item"] = s->name; + data["value"]["ip"] = s->ip; + data["value"]["local"] = islocal; + data["value"]["dir"] = params.dir; + data["value"]["filename"] = filename; + + for(auto ss : servers){ + if(s->server == ss->ip && ss->connected){ + ss->client->send(data.dump()); + downloading_last_media_total++; + break; + } + } + } + if(downloading_last_media_total == 0){ + downloading_last_media_flag = 0; + } + }).detach(); } -void GoProMaster::download_single_media(const std::string server, const std::string ip, const std::string folder, MediaInfo media){ +void GoProMaster::download_single_media(const std::string server, const std::string ip, const std::string filepath, MediaInfo media){ std::thread([=](){ if(params.put_finish){ downloading_last_media_flag = 2; diff --git a/src/master/GoProMaster.h b/src/master/GoProMaster.h index 6aa636cc..cead4151 100644 --- a/src/master/GoProMaster.h +++ b/src/master/GoProMaster.h @@ -99,7 +99,7 @@ class GoProMaster { void media_only(const std::string command, std::string target = ""); void download_last_media(const std::string ip, const DownloadMediaParameters params); void download_all_media(const std::string server, const std::string ip, const std::string folder, std::vector media_list); - void download_single_media(const std::string server, const std::string ip, const std::string folder, MediaInfo media); + void download_single_media(const std::string server, const std::string ip, const std::string filepath, MediaInfo media); void get_media_info(const std::string server, const std::string ip, const std::string path); void get_media_list(const std::string server, const std::string ip); From 9a9e77f2b088f7d4612edd1c228f6535cf5a9e47 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Thu, 7 May 2026 17:30:35 +0800 Subject: [PATCH 53/64] Update master signal send and server d single and d all receiver --- src/master/GoProMaster.cpp | 155 +++++++++++++------------------------ src/master/GoProMaster.h | 6 +- src/server/main.cpp | 20 +++++ 3 files changed, 75 insertions(+), 106 deletions(-) diff --git a/src/master/GoProMaster.cpp b/src/master/GoProMaster.cpp index f3b4ea1a..e67c629e 100644 --- a/src/master/GoProMaster.cpp +++ b/src/master/GoProMaster.cpp @@ -282,14 +282,15 @@ void GoProMaster::media_only(const std::string command, std::string target){ } void GoProMaster::download_last_media(const std::string ip, const DownloadMediaParameters params){ + if(downloading_media_flag > 0) return; std::thread([=](){ if(params.put_finish){ - downloading_last_media_flag = 2; + downloading_media_flag = 2; }else{ - downloading_last_media_flag = 1; + downloading_media_flag = 1; } - downloading_last_media_total = 0; - downloading_last_media_done = 0; + downloading_media_total = 0; + downloading_media_done = 0; for(auto& s : cameras){ if(!s->connected) continue; @@ -336,145 +337,93 @@ void GoProMaster::download_last_media(const std::string ip, const DownloadMediaP for(auto ss : servers){ if(s->server == ss->ip && ss->connected){ ss->client->send(data.dump()); - downloading_last_media_total++; + downloading_media_total++; break; } } } - if(downloading_last_media_total == 0){ - downloading_last_media_flag = 0; + if(downloading_media_total == 0){ + downloading_media_flag = 0; } }).detach(); } void GoProMaster::download_all_media(const std::string server, const std::string ip, const std::string folder, std::vector media_list){ + if(downloading_media_flag > 0) return; std::thread([=](){ - if(params.put_finish){ - downloading_last_media_flag = 2; - }else{ - downloading_last_media_flag = 1; - } - downloading_last_media_total = 0; - downloading_last_media_done = 0; + downloading_media_flag = 1; + downloading_media_total = 0; + downloading_media_done = 0; - for(auto& s : cameras){ - if(!s->connected) continue; - if(ip.size() == 0 || s->ip != ip || s->server != server) continue; + int32_t index = findCamera(server, ip); + if(index >= 0){ + const CameraInfo s = getCamera_Clone(index); std::string ext = fs::path(s->last_media).extension().string(); - std::string filename = s->name; - if(filename.size() == 0 || s->name.size() == 0) { - std::cerr << "[download_last_media] filename size is 0, we just skip..." << std::endl; - continue; - } - size_t filename_size = filename.size(); - std::cout << "[download_last_media] \ttype: " << params.type << std::endl; - std::cout << "[download_last_media] \tfilename: " << filename.c_str() << std::endl; - if(params.c_count > 0){ - std::string ccc = ""; - for(int32_t i = 0; i < params.c_count && i < filename_size; i++){ - if(params.type == 1){ - ccc += filename.at(0); - filename.erase(filename.begin()); - } - if(params.type == 2){ - ccc += filename.at(filename.size() - 1); - filename.erase(filename.begin() + filename.size() - 1); - } - } - if(params.type == 2){ - ccc.reserve(); - } - filename = ccc; - } - filename += ext; bool islocal = s->server == "127.0.0.1"; + fs::path p(filepath); json data = json::object(); data["key"] = "media"; data["value"] = json::object(); - data["value"]["name"] = "url"; - data["value"]["item"] = s->name; - data["value"]["ip"] = s->ip; + data["value"]["name"] = "d_all"; + data["value"]["item"] = s.name; + data["value"]["ip"] = s.ip; data["value"]["local"] = islocal; - data["value"]["dir"] = params.dir; - data["value"]["filename"] = filename; + data["value"]["dir"] = folder; + data["value"]["filenames"] = json::array(); + for(auto& m : media_list){ + data["value"]["filenames"].push_back(m.filename); + } + for(auto ss : servers){ - if(s->server == ss->ip && ss->connected){ + if(s.server == ss->ip && ss->connected){ ss->client->send(data.dump()); - downloading_last_media_total++; + downloading_media_total++; break; } } } - if(downloading_last_media_total == 0){ - downloading_last_media_flag = 0; + if(downloading_media_total == 0){ + downloading_media_flag = 0; } }).detach(); } void GoProMaster::download_single_media(const std::string server, const std::string ip, const std::string filepath, MediaInfo media){ + if(downloading_media_flag > 0) return; std::thread([=](){ - if(params.put_finish){ - downloading_last_media_flag = 2; - }else{ - downloading_last_media_flag = 1; - } - downloading_last_media_total = 0; - downloading_last_media_done = 0; + downloading_media_flag = 1; + downloading_media_total = 0; + downloading_media_done = 0; - for(auto& s : cameras){ - if(!s->connected) continue; - if(ip.size() == 0 || s->ip != ip || s->server != server) continue; + int32_t index = findCamera(server, ip); + if(index >= 0){ + const CameraInfo s = getCamera_Clone(index); std::string ext = fs::path(s->last_media).extension().string(); - std::string filename = s->name; - if(filename.size() == 0 || s->name.size() == 0) { - std::cerr << "[download_last_media] filename size is 0, we just skip..." << std::endl; - continue; - } - size_t filename_size = filename.size(); - std::cout << "[download_last_media] \ttype: " << params.type << std::endl; - std::cout << "[download_last_media] \tfilename: " << filename.c_str() << std::endl; - if(params.c_count > 0){ - std::string ccc = ""; - for(int32_t i = 0; i < params.c_count && i < filename_size; i++){ - if(params.type == 1){ - ccc += filename.at(0); - filename.erase(filename.begin()); - } - if(params.type == 2){ - ccc += filename.at(filename.size() - 1); - filename.erase(filename.begin() + filename.size() - 1); - } - } - if(params.type == 2){ - ccc.reserve(); - } - filename = ccc; - } - filename += ext; bool islocal = s->server == "127.0.0.1"; + fs::path p(filepath); json data = json::object(); data["key"] = "media"; data["value"] = json::object(); - data["value"]["name"] = "url"; - data["value"]["item"] = s->name; - data["value"]["ip"] = s->ip; + data["value"]["name"] = "d_single"; + data["value"]["item"] = s.name; + data["value"]["ip"] = s.ip; data["value"]["local"] = islocal; - data["value"]["dir"] = params.dir; - data["value"]["filename"] = filename; + data["value"]["dir"] = p.parent_path().string(); + data["value"]["filename"] = p.filename().string(); for(auto ss : servers){ - if(s->server == ss->ip && ss->connected){ + if(s.server == ss->ip && ss->connected){ ss->client->send(data.dump()); - downloading_last_media_total++; + downloading_media_total++; break; } } } - if(downloading_last_media_total == 0){ - downloading_last_media_flag = 0; + if(downloading_media_total == 0){ + downloading_media_flag = 0; } }).detach(); } @@ -1057,16 +1006,16 @@ void GoProMaster::processMessage(const std::string& server, const std::string& m size_t size = requests::downloadFile(urls.c_str(), path_target.c_str(), [&urls, &path_target](size_t received_bytes, size_t total_bytes){ std::cout << "[last_media] download " << urls << " => " << path_target << " " << received_bytes << " / " << total_bytes << std::endl; }); - downloading_last_media_done++; - if(downloading_last_media_done == downloading_last_media_total){ - if(downloading_last_media_flag == 2){ + downloading_media_done++; + if(downloading_media_done == downloading_media_total){ + if(downloading_media_flag == 2){ std::string finish_file = dir + "/" + "finish.txt"; FILE* f = fopen(finish_file.c_str(), "wb"); fclose(f); } - downloading_last_media_total = 0; - downloading_last_media_done = 0; - downloading_last_media_flag = 0; + downloading_media_total = 0; + downloading_media_done = 0; + downloading_media_flag = 0; } } } diff --git a/src/master/GoProMaster.h b/src/master/GoProMaster.h index cead4151..6a420f28 100644 --- a/src/master/GoProMaster.h +++ b/src/master/GoProMaster.h @@ -207,9 +207,9 @@ class GoProMaster { * 1: On (no finish txt) * 2: On (with finish txt) */ - std::atomic_char32_t downloading_last_media_flag = 0; - std::atomic_char32_t downloading_last_media_total; - std::atomic_char32_t downloading_last_media_done; + std::atomic_char32_t downloading_media_flag = 0; + std::atomic_char32_t downloading_media_total; + std::atomic_char32_t downloading_media_done; /** * The background thread for fetch update from all websocket server and update etc... diff --git a/src/server/main.cpp b/src/server/main.cpp index e2fcc802..6c081d69 100644 --- a/src/server/main.cpp +++ b/src/server/main.cpp @@ -340,6 +340,7 @@ void MediaAction(const WebSocketChannelPtr& channel, json j){ std::string ip = ""; std::string dir = ""; std::string filename = ""; + json filenames = json::array(); bool local = true; json r = json::object(); @@ -364,6 +365,9 @@ void MediaAction(const WebSocketChannelPtr& channel, json j){ if(j["filename"].is_string()){ filename = j["filename"].get(); } + if(j["filename"].is_array()){ + filenames = j["filename"]; + } if(j["local"].is_boolean()){ local = j["local"].get(); } @@ -402,6 +406,22 @@ void MediaAction(const WebSocketChannelPtr& channel, json j){ r["local"] = local; r["data"] = controller.getMediaInfoData(ip, path, local); channel->send(getPacket("media:info", r)); + }else if(name == "d_single"){ + std::lock_guard lock(download_mtx); + r["local"] = local; + r["item"] = item; + r["dir"] = dir; + r["filename"] = filename; + r["path"] = controller.getFetchURL(ip, local); + channel->send(getPacket("media:url", r)); + }else if(name == "d_all"){ + std::lock_guard lock(download_mtx); + r["local"] = local; + r["item"] = item; + r["dir"] = dir; + r["filename"] = filename; + r["path"] = controller.getFetchURL(ip, local); + channel->send(getPacket("media:url", r)); }else{ channel->send(getPacket("media:unknown", r)); } From f63c36905d51395f2d45263ff5b77dc2f812168b Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Thu, 7 May 2026 17:35:38 +0800 Subject: [PATCH 54/64] Update server --- src/server/GoProController.h | 2 ++ src/server/controller/media.cpp | 8 ++++++++ src/server/main.cpp | 16 ++++++++++------ 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/server/GoProController.h b/src/server/GoProController.h index aaef29ed..66fa2aa1 100644 --- a/src/server/GoProController.h +++ b/src/server/GoProController.h @@ -330,6 +330,8 @@ class GoProController { /// - target /// std::string getFetchURL(std::string target_ip, bool is_local); + std::string getSingleFetchURL(std::string target_ip, const std::string filename, bool is_local); + std::string getAllFetchURL(std::string target_ip, std::vector filenames, bool is_local); std::string getThumbnailData(std::string target_ip, std::string path, bool is_local); std::string getMediaInfoData(std::string target_ip, std::string path, bool is_local); #pragma endregion diff --git a/src/server/controller/media.cpp b/src/server/controller/media.cpp index 52f62d11..cf0e1886 100644 --- a/src/server/controller/media.cpp +++ b/src/server/controller/media.cpp @@ -161,6 +161,14 @@ std::string GoProController::getFetchURL(std::string target_ip, bool is_local){ } } +std::string getSingleFetchURL(std::string target_ip, const std::string filename, bool is_local){ + return ""; +} + +std::string getAllFetchURL(std::string target_ip, std::vector filenames, bool is_local){ + return ""; +} + std::string GoProController::getThumbnailData(std::string target_ip, std::string path, bool is_local){ std::cout << "Http GET /thumbnail " << target_ip << ", " << is_local << std::endl; diff --git a/src/server/main.cpp b/src/server/main.cpp index 6c081d69..620f1526 100644 --- a/src/server/main.cpp +++ b/src/server/main.cpp @@ -340,7 +340,7 @@ void MediaAction(const WebSocketChannelPtr& channel, json j){ std::string ip = ""; std::string dir = ""; std::string filename = ""; - json filenames = json::array(); + std::vector filenames = std::vector; bool local = true; json r = json::object(); @@ -365,8 +365,12 @@ void MediaAction(const WebSocketChannelPtr& channel, json j){ if(j["filename"].is_string()){ filename = j["filename"].get(); } - if(j["filename"].is_array()){ - filenames = j["filename"]; + if(j["filenames"].is_array()){ + for(size_t i = 0; i < j["filenames"].size(); i++){ + if(j["filenames"][i].is_string()){ + filenames.push_back(j["filenames"][i].get()); + } + } } if(j["local"].is_boolean()){ local = j["local"].get(); @@ -412,15 +416,15 @@ void MediaAction(const WebSocketChannelPtr& channel, json j){ r["item"] = item; r["dir"] = dir; r["filename"] = filename; - r["path"] = controller.getFetchURL(ip, local); + r["path"] = controller.getSingleFetchURL(ip, filename, local); channel->send(getPacket("media:url", r)); }else if(name == "d_all"){ std::lock_guard lock(download_mtx); r["local"] = local; r["item"] = item; r["dir"] = dir; - r["filename"] = filename; - r["path"] = controller.getFetchURL(ip, local); + r["filenames"] = filenames; + r["paths"] = controller.getAllFetchURL(ip, filenames, local); channel->send(getPacket("media:url", r)); }else{ channel->send(getPacket("media:unknown", r)); From f8eb5114f6a9a945f368175a76bdfc7c40365000 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Thu, 7 May 2026 18:02:53 +0800 Subject: [PATCH 55/64] Update server media controoler script details --- src/server/controller/media.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/server/controller/media.cpp b/src/server/controller/media.cpp index cf0e1886..aba16675 100644 --- a/src/server/controller/media.cpp +++ b/src/server/controller/media.cpp @@ -161,11 +161,23 @@ std::string GoProController::getFetchURL(std::string target_ip, bool is_local){ } } -std::string getSingleFetchURL(std::string target_ip, const std::string filename, bool is_local){ +std::string GoProController::getSingleFetchURL(std::string target_ip, const std::string filename, bool is_local){ + std::cout << "Http GET /single_media " << target_ip << ", " << is_local << std::endl; + + if (target_ip.empty()) { + std::cerr << "[single_media] " << target_ip << " Missing ip parameter" << std::endl; + return ""; + } return ""; } -std::string getAllFetchURL(std::string target_ip, std::vector filenames, bool is_local){ +std::string GoProController::getAllFetchURL(std::string target_ip, std::vector filenames, bool is_local){ + std::cout << "Http GET /all_media " << target_ip << ", " << is_local << std::endl; + + if (target_ip.empty()) { + std::cerr << "[all_media] " << target_ip << " Missing ip parameter" << std::endl; + return ""; + } return ""; } From 4cee278c2137e5199072e5da3daccc5a645d730f Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Thu, 7 May 2026 18:04:09 +0800 Subject: [PATCH 56/64] update same --- src/server/controller/media.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/server/controller/media.cpp b/src/server/controller/media.cpp index aba16675..03b3e8ca 100644 --- a/src/server/controller/media.cpp +++ b/src/server/controller/media.cpp @@ -168,7 +168,13 @@ std::string GoProController::getSingleFetchURL(std::string target_ip, const std: std::cerr << "[single_media] " << target_ip << " Missing ip parameter" << std::endl; return ""; } - return ""; + + try{ + return ""; + }catch(const std::exception& ex){ + std::cerr << ex.what() << std::endl; + return ""; + } } std::string GoProController::getAllFetchURL(std::string target_ip, std::vector filenames, bool is_local){ @@ -178,7 +184,13 @@ std::string GoProController::getAllFetchURL(std::string target_ip, std::vector Date: Fri, 8 May 2026 10:26:58 +0800 Subject: [PATCH 57/64] Update --- src/server/GoProController.h | 2 +- src/server/controller/media.cpp | 64 +++++++++++++++++++++++++++++++-- src/server/main.cpp | 6 +++- 3 files changed, 67 insertions(+), 5 deletions(-) diff --git a/src/server/GoProController.h b/src/server/GoProController.h index 66fa2aa1..8b5ec740 100644 --- a/src/server/GoProController.h +++ b/src/server/GoProController.h @@ -331,7 +331,7 @@ class GoProController { /// std::string getFetchURL(std::string target_ip, bool is_local); std::string getSingleFetchURL(std::string target_ip, const std::string filename, bool is_local); - std::string getAllFetchURL(std::string target_ip, std::vector filenames, bool is_local); + std::vector getAllFetchURL(std::string target_ip, std::vector filenames, bool is_local); std::string getThumbnailData(std::string target_ip, std::string path, bool is_local); std::string getMediaInfoData(std::string target_ip, std::string path, bool is_local); #pragma endregion diff --git a/src/server/controller/media.cpp b/src/server/controller/media.cpp index 03b3e8ca..ad8f4e8c 100644 --- a/src/server/controller/media.cpp +++ b/src/server/controller/media.cpp @@ -170,14 +170,41 @@ std::string GoProController::getSingleFetchURL(std::string target_ip, const std: } try{ - return ""; + std::string gopro_url = "http://" + target_ip + ":8080/videos/DCIM/" + filename + "?download=true"; + if(is_local){ + std::cout << "[last_media] return value: " << target_ip << " => " << gopro_url << std::endl; + return gopro_url; + }else{ + int32_t t = 0; + std::string download_path = "temp.download"; + while(fs::exists("res/" + download_path)){ + download_path = "temp.download" + std::to_string(t); + t++; + } + std::cout << "[last_media] try download " << gopro_url.c_str() << std::endl; +#ifdef SERVER_MEDIA_DOWNLOAD_LOG + auto start = std::chrono::high_resolution_clock::now(); +#endif + size_t size = requests::downloadFile(gopro_url.c_str(), ("res/" + download_path).c_str(), [&target_ip, &start](size_t received_bytes, size_t total_bytes){ +#ifdef SERVER_MEDIA_DOWNLOAD_LOG + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = end - start; + if(elapsed.count() >= SERVER_MEDIA_DOWNLOAD_PERIOD){ + start = end; + std::cout << "[last_media] download " << target_ip << " " << received_bytes << " / " << total_bytes << std::endl; + } +#endif + }); + std::cout << "[last_media] return value: " << target_ip << " => " << download_path << std::endl; + return download_path; + } }catch(const std::exception& ex){ std::cerr << ex.what() << std::endl; return ""; } } -std::string GoProController::getAllFetchURL(std::string target_ip, std::vector filenames, bool is_local){ +std::vector GoProController::getAllFetchURL(std::string target_ip, std::vector filenames, bool is_local){ std::cout << "Http GET /all_media " << target_ip << ", " << is_local << std::endl; if (target_ip.empty()) { @@ -186,7 +213,38 @@ std::string GoProController::getAllFetchURL(std::string target_ip, std::vector results = std::vector(); + for(auto filename : filenames){ + std::string gopro_url = "http://" + target_ip + ":8080/videos/DCIM/" + filename + "?download=true"; + if(is_local){ + std::cout << "[last_media] return value: " << target_ip << " => " << gopro_url << std::endl; + results.push_back(gopro_url); + }else{ + int32_t t = 0; + std::string download_path = "temp.download"; + while(fs::exists("res/" + download_path)){ + download_path = "temp.download" + std::to_string(t); + t++; + } + std::cout << "[last_media] try download " << gopro_url.c_str() << std::endl; + #ifdef SERVER_MEDIA_DOWNLOAD_LOG + auto start = std::chrono::high_resolution_clock::now(); + #endif + size_t size = requests::downloadFile(gopro_url.c_str(), ("res/" + download_path).c_str(), [&target_ip, &start](size_t received_bytes, size_t total_bytes){ + #ifdef SERVER_MEDIA_DOWNLOAD_LOG + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = end - start; + if(elapsed.count() >= SERVER_MEDIA_DOWNLOAD_PERIOD){ + start = end; + std::cout << "[last_media] download " << target_ip << " " << received_bytes << " / " << total_bytes << std::endl; + } + #endif + }); + std::cout << "[last_media] return value: " << target_ip << " => " << download_path << std::endl; + results.push_back(download_path); + } + } + return results; }catch(const std::exception& ex){ std::cerr << ex.what() << std::endl; return ""; diff --git a/src/server/main.cpp b/src/server/main.cpp index 620f1526..df9d3c0a 100644 --- a/src/server/main.cpp +++ b/src/server/main.cpp @@ -420,11 +420,15 @@ void MediaAction(const WebSocketChannelPtr& channel, json j){ channel->send(getPacket("media:url", r)); }else if(name == "d_all"){ std::lock_guard lock(download_mtx); + std::vector results = controller.getAllFetchURL(ip, filenames, local); r["local"] = local; r["item"] = item; r["dir"] = dir; r["filenames"] = filenames; - r["paths"] = controller.getAllFetchURL(ip, filenames, local); + r["paths"] = json::array(); + for(size_t i = 0; i < results.size(); i++){ + r["paths"].push_back(results.at(i)); + } channel->send(getPacket("media:url", r)); }else{ channel->send(getPacket("media:unknown", r)); From 19d3036e480c82c748837fa0edab874d9cdce19c Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Fri, 8 May 2026 10:29:16 +0800 Subject: [PATCH 58/64] Update response for server --- src/server/GoProController.h | 2 +- src/server/controller/media.cpp | 6 +++--- src/server/main.cpp | 7 +++++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/server/GoProController.h b/src/server/GoProController.h index 8b5ec740..135db35e 100644 --- a/src/server/GoProController.h +++ b/src/server/GoProController.h @@ -331,7 +331,7 @@ class GoProController { /// std::string getFetchURL(std::string target_ip, bool is_local); std::string getSingleFetchURL(std::string target_ip, const std::string filename, bool is_local); - std::vector getAllFetchURL(std::string target_ip, std::vector filenames, bool is_local); + std::vector> getAllFetchURL(std::string target_ip, std::vector filenames, bool is_local); std::string getThumbnailData(std::string target_ip, std::string path, bool is_local); std::string getMediaInfoData(std::string target_ip, std::string path, bool is_local); #pragma endregion diff --git a/src/server/controller/media.cpp b/src/server/controller/media.cpp index ad8f4e8c..3a39c8b5 100644 --- a/src/server/controller/media.cpp +++ b/src/server/controller/media.cpp @@ -213,12 +213,12 @@ std::vector GoProController::getAllFetchURL(std::string target_ip, } try{ - std::vector results = std::vector(); + std::vector> results = std::vector>(); for(auto filename : filenames){ std::string gopro_url = "http://" + target_ip + ":8080/videos/DCIM/" + filename + "?download=true"; if(is_local){ std::cout << "[last_media] return value: " << target_ip << " => " << gopro_url << std::endl; - results.push_back(gopro_url); + results.push_back(std::make_pair(filename, gopro_url)); }else{ int32_t t = 0; std::string download_path = "temp.download"; @@ -241,7 +241,7 @@ std::vector GoProController::getAllFetchURL(std::string target_ip, #endif }); std::cout << "[last_media] return value: " << target_ip << " => " << download_path << std::endl; - results.push_back(download_path); + results.push_back(std::make_pair(filename, download_path)); } } return results; diff --git a/src/server/main.cpp b/src/server/main.cpp index df9d3c0a..7c07ce68 100644 --- a/src/server/main.cpp +++ b/src/server/main.cpp @@ -420,14 +420,17 @@ void MediaAction(const WebSocketChannelPtr& channel, json j){ channel->send(getPacket("media:url", r)); }else if(name == "d_all"){ std::lock_guard lock(download_mtx); - std::vector results = controller.getAllFetchURL(ip, filenames, local); + std::vector> results = controller.getAllFetchURL(ip, filenames, local); r["local"] = local; r["item"] = item; r["dir"] = dir; r["filenames"] = filenames; r["paths"] = json::array(); for(size_t i = 0; i < results.size(); i++){ - r["paths"].push_back(results.at(i)); + json buffer = json::object(); + buffer["filename"] = results.at(i).first; + buffer["path"] = results.at(i).second; + r["paths"].push_back(buffer); } channel->send(getPacket("media:url", r)); }else{ From 15e9c78a081cfa8888d42f6cc24a15655ab31565 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Fri, 8 May 2026 10:31:45 +0800 Subject: [PATCH 59/64] Update server codebase typo --- src/server/controller/media.cpp | 6 +++--- src/server/main.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/server/controller/media.cpp b/src/server/controller/media.cpp index 3a39c8b5..1c8b6ea8 100644 --- a/src/server/controller/media.cpp +++ b/src/server/controller/media.cpp @@ -204,12 +204,12 @@ std::string GoProController::getSingleFetchURL(std::string target_ip, const std: } } -std::vector GoProController::getAllFetchURL(std::string target_ip, std::vector filenames, bool is_local){ +std::vector> GoProController::getAllFetchURL(std::string target_ip, std::vector filenames, bool is_local){ std::cout << "Http GET /all_media " << target_ip << ", " << is_local << std::endl; if (target_ip.empty()) { std::cerr << "[all_media] " << target_ip << " Missing ip parameter" << std::endl; - return ""; + return std::vector>(); } try{ @@ -247,7 +247,7 @@ std::vector GoProController::getAllFetchURL(std::string target_ip, return results; }catch(const std::exception& ex){ std::cerr << ex.what() << std::endl; - return ""; + return std::vector>();; } } diff --git a/src/server/main.cpp b/src/server/main.cpp index 7c07ce68..eb3ac625 100644 --- a/src/server/main.cpp +++ b/src/server/main.cpp @@ -340,7 +340,7 @@ void MediaAction(const WebSocketChannelPtr& channel, json j){ std::string ip = ""; std::string dir = ""; std::string filename = ""; - std::vector filenames = std::vector; + std::vector filenames = std::vector(); bool local = true; json r = json::object(); From eb4e2798ecca54b65feaab4129fc27f486ef3863 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Mon, 11 May 2026 16:11:05 +0800 Subject: [PATCH 60/64] Added apply cancel --- src/master/GoProMaster.cpp | 30 +++++++++++++++---- src/master/GoProMaster.h | 1 + .../windows/camera_list/display_state.cpp | 4 ++- src/master/windows/inspector/inspector.cpp | 21 +++++++++---- src/server/main.cpp | 7 +++-- 5 files changed, 47 insertions(+), 16 deletions(-) diff --git a/src/master/GoProMaster.cpp b/src/master/GoProMaster.cpp index e67c629e..2f5fce3d 100644 --- a/src/master/GoProMaster.cpp +++ b/src/master/GoProMaster.cpp @@ -358,10 +358,9 @@ void GoProMaster::download_all_media(const std::string server, const std::string int32_t index = findCamera(server, ip); if(index >= 0){ const CameraInfo s = getCamera_Clone(index); - std::string ext = fs::path(s->last_media).extension().string(); - bool islocal = s->server == "127.0.0.1"; + std::string ext = fs::path(s.last_media).extension().string(); + bool islocal = s.server == "127.0.0.1"; - fs::path p(filepath); json data = json::object(); data["key"] = "media"; data["value"] = json::object(); @@ -400,8 +399,8 @@ void GoProMaster::download_single_media(const std::string server, const std::str int32_t index = findCamera(server, ip); if(index >= 0){ const CameraInfo s = getCamera_Clone(index); - std::string ext = fs::path(s->last_media).extension().string(); - bool islocal = s->server == "127.0.0.1"; + std::string ext = fs::path(s.last_media).extension().string(); + bool islocal = s.server == "127.0.0.1"; fs::path p(filepath); json data = json::object(); @@ -546,6 +545,19 @@ void GoProMaster::quickApplyAll(const CameraInfo& target){ } } +void GoProMaster::stopApplyAll(const CameraInfo& target){ + std::thread([=](){ + for (auto& s : servers) { + if (!s->connected) continue; + json get_status = json::object(); + get_status["key"] = "query"; + get_status["value"] = json::object(); + get_status["value"]["name"] = "setall_cancel"; + s->client->send(get_status.dump()); + } + }).detach(); +} + bool GoProMaster::directoryExists(const std::string& path) { if (fs::exists(path) && fs::is_directory(path)) { return true; @@ -1072,7 +1084,7 @@ void GoProMaster::processMessage(const std::string& server, const std::string& m if(_camera_media_list_feedback != NULL) _camera_media_list_feedback(media_list); } - else if(key == "thumbnail"){ + else if(key == "media:thumbnail"){ if(!data["value"]["data"].is_string()){ std::cerr << "Invalid message from " << server << ": " << msg << std::endl; std::cerr << "media:thumbnail, return value should be string" << std::endl; @@ -1080,6 +1092,12 @@ void GoProMaster::processMessage(const std::string& server, const std::string& m } std::vector raw_data = decodeBase64(data["value"]["data"].get()); + } + else if(key == "media:d_single"){ + + } + else if(key == "media:d_all"){ + } else{ std::cerr << "Invalid message from " << server << ": " << msg << std::endl; diff --git a/src/master/GoProMaster.h b/src/master/GoProMaster.h index 6a420f28..358ebb1b 100644 --- a/src/master/GoProMaster.h +++ b/src/master/GoProMaster.h @@ -109,6 +109,7 @@ class GoProMaster { void apply(const std::string& ip, const std::string& target, const int32_t id, const int32_t value); void applyAll(const std::string& ip, const json& res); void quickApplyAll(const CameraInfo& target); + void stopApplyAll(const CameraInfo& target); bool directoryExists(const std::string& path); diff --git a/src/master/windows/camera_list/display_state.cpp b/src/master/windows/camera_list/display_state.cpp index 1447ad29..0fa96cf2 100644 --- a/src/master/windows/camera_list/display_state.cpp +++ b/src/master/windows/camera_list/display_state.cpp @@ -278,9 +278,11 @@ void CameraListWindow::draw_group_state(const CameraInfo& c){ ); std::string record_time; + bool record_time_red = false; if(status[std::to_string(VIDEO_ENCODING_DURATION_ID)].is_number_integer()){ int32_t re = status[std::to_string(VIDEO_ENCODING_DURATION_ID)].get(); + record_time_red = re > 0; record_time = toTimeCode(re); } @@ -289,7 +291,7 @@ void CameraListWindow::draw_group_state(const CameraInfo& c){ center.x + ( record_time_size.x / -2.0F ), image_pos.y + frame_padding.y ); - draw_list->AddText(record_time_min, col_white, record_time.c_str()); + draw_list->AddText(record_time_min, record_time_red ? col_red : col_white, record_time.c_str()); } // Preset mode if(c.connected){ diff --git a/src/master/windows/inspector/inspector.cpp b/src/master/windows/inspector/inspector.cpp index b04c5624..53de9197 100644 --- a/src/master/windows/inspector/inspector.cpp +++ b/src/master/windows/inspector/inspector.cpp @@ -148,12 +148,21 @@ void InspectorWindow::render(){ ImGui::EndDisabled(); ImGui::SameLine(); - ImGui::BeginDisabled(should_disabled || state->applying_all); - if(ImGui::Button("Quick Apply All##Inspector_Bar_Item")){ - if(s != -1){ - const CameraInfo c = master->getCamera_Clone(s); - master->quickApplyAll(c); - state->applying_all = true; + ImGui::BeginDisabled(should_disabled); + if(state->applying_all){ + if(ImGui::Button("Stop Apply All##Inspector_Bar_Item")){ + if(s != -1){ + const CameraInfo c = master->getCamera_Clone(s); + master->stopApplyAll(c); + } + } + }else{ + if(ImGui::Button("Quick Apply All##Inspector_Bar_Item")){ + if(s != -1){ + const CameraInfo c = master->getCamera_Clone(s); + master->quickApplyAll(c); + state->applying_all = true; + } } } ImGui::EndDisabled(); diff --git a/src/server/main.cpp b/src/server/main.cpp index eb3ac625..3e105090 100644 --- a/src/server/main.cpp +++ b/src/server/main.cpp @@ -234,7 +234,8 @@ void QueryAction(const WebSocketChannelPtr& channel, json j){ channel->send(getPacket("query:set", r)); } else if(name == "setall_cancel"){ - + controller.setSettingCancelAll(); + channel->send(getPacket("query:setall_cancel", r)); } else if(name == "setall"){ resultText = controller.setSettingAll(source, target, preset, jvalue); @@ -417,7 +418,7 @@ void MediaAction(const WebSocketChannelPtr& channel, json j){ r["dir"] = dir; r["filename"] = filename; r["path"] = controller.getSingleFetchURL(ip, filename, local); - channel->send(getPacket("media:url", r)); + channel->send(getPacket("media:d_single", r)); }else if(name == "d_all"){ std::lock_guard lock(download_mtx); std::vector> results = controller.getAllFetchURL(ip, filenames, local); @@ -432,7 +433,7 @@ void MediaAction(const WebSocketChannelPtr& channel, json j){ buffer["path"] = results.at(i).second; r["paths"].push_back(buffer); } - channel->send(getPacket("media:url", r)); + channel->send(getPacket("media:d_all", r)); }else{ channel->send(getPacket("media:unknown", r)); } From f6ef92537152b723985441536eb9564f3c7022c1 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Mon, 11 May 2026 16:12:38 +0800 Subject: [PATCH 61/64] Added thread safe cancel boolean on server side --- src/server/GoProController.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/GoProController.h b/src/server/GoProController.h index 135db35e..dc3dee12 100644 --- a/src/server/GoProController.h +++ b/src/server/GoProController.h @@ -420,7 +420,7 @@ class GoProController { /// State of current server /// Is applying something /// - bool applying_cancel = false; + std::atomic applying_cancel = false; /// /// The handle for mdns service manager /// From 634422dcf6a6844623b0b9dee1f59934f44f6487 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Tue, 12 May 2026 10:31:52 +0800 Subject: [PATCH 62/64] Added thumbnail assign methid --- src/master/GoProMaster.cpp | 2 +- src/master/data/state.h | 2 ++ src/master/main.cpp | 43 ++++++++++++----------- src/master/popup/media_browser_popwin.cpp | 42 ++++++++++++++++++++++ src/master/popup/media_browser_popwin.h | 9 +++++ src/server/private/webcam.cpp | 1 - 6 files changed, 76 insertions(+), 23 deletions(-) diff --git a/src/master/GoProMaster.cpp b/src/master/GoProMaster.cpp index 2f5fce3d..f1576115 100644 --- a/src/master/GoProMaster.cpp +++ b/src/master/GoProMaster.cpp @@ -1032,7 +1032,7 @@ void GoProMaster::processMessage(const std::string& server, const std::string& m } } else if(key == "media:info"){ - + } else if(key == "media:list"){ std::vector media_list = std::vector(); diff --git a/src/master/data/state.h b/src/master/data/state.h index 8c43ed20..cb87ef83 100644 --- a/src/master/data/state.h +++ b/src/master/data/state.h @@ -7,6 +7,7 @@ #pragma once #include #include +#include #include using json = nlohmann::json; @@ -26,6 +27,7 @@ struct MediaInfo { }; struct GlobalState { + SDL_Renderer* m_renderer; bool done; int32_t applying_all_count = 0; bool applying_all; diff --git a/src/master/main.cpp b/src/master/main.cpp index 360e90f8..70a2cb3c 100644 --- a/src/master/main.cpp +++ b/src/master/main.cpp @@ -26,27 +26,27 @@ c[d] = a; \ a = std::make_shared(r, gui, global_state, master); \ c[d] = a; \ -std::queue command_queue = std::queue(); -std::shared_ptr master = std::make_shared(); -std::shared_ptr gui; -std::shared_ptr servers; -std::shared_ptr presets; -std::shared_ptr global_state = std::make_shared(); - -std::shared_ptr camera_list_win; -std::shared_ptr inspector_win; -std::shared_ptr websocket_win; -std::shared_ptr style_setting_win; -std::shared_ptr windows_array[4]; - -std::shared_ptr add_camera_popwin; -std::shared_ptr scan_camera_popwin; -std::shared_ptr start_webcam_popwin; -std::shared_ptr preview_popwin; -std::shared_ptr add_preset_popwin; -std::shared_ptr preset_manager_popwin; -std::shared_ptr media_browser_popwin; -std::shared_ptr pop_windows_array[7]; +static std::queue command_queue = std::queue(); +static std::shared_ptr master = std::make_shared(); +static std::shared_ptr gui; +static std::shared_ptr servers; +static std::shared_ptr presets; +static std::shared_ptr global_state = std::make_shared(); + +static std::shared_ptr camera_list_win; +static std::shared_ptr inspector_win; +static std::shared_ptr websocket_win; +static std::shared_ptr style_setting_win; +static std::shared_ptr windows_array[4]; + +static std::shared_ptr add_camera_popwin; +static std::shared_ptr scan_camera_popwin; +static std::shared_ptr start_webcam_popwin; +static std::shared_ptr preview_popwin; +static std::shared_ptr add_preset_popwin; +static std::shared_ptr preset_manager_popwin; +static std::shared_ptr media_browser_popwin; +static std::shared_ptr pop_windows_array[7]; // All the window flags ExecutionType execution_type = ExecutionType::SetAll; @@ -189,6 +189,7 @@ int main(int, char**) SDL_GL_MakeCurrent(window, gl_context); } SDL_Renderer* renderer = SDL_CreateRenderer(window, NULL); + global_state->m_renderer = renderer; servers = std::make_shared(loadServerList()); gui = std::make_shared(loadGUI()); diff --git a/src/master/popup/media_browser_popwin.cpp b/src/master/popup/media_browser_popwin.cpp index 4c67f855..b76a8d79 100644 --- a/src/master/popup/media_browser_popwin.cpp +++ b/src/master/popup/media_browser_popwin.cpp @@ -165,4 +165,46 @@ void MediaBrowserPopup::download_file_callback(const std::string fullpath){ } } } +} + +void MediaBrowserPopup::add_thumbnail(const std::string filename, const std::vector rawData, const std::pair resolution){ + thumbnail_rawData.insert_or_assign(filename, std::make_pair(rawData, resolution)); +} + +void MediaBrowserPopup::convert_rawData_to_texture(){ + for(auto& i : thumbnail_rawData){ + const std::string& filename = i.first; + const std::vector& rawData = i.second.first; + const std::pair& resolution = i.second.second; + + SDL_Texture* texture = SDL_CreateTexture(state->m_renderer, + SDL_PIXELFORMAT_RGBA8888, + SDL_TEXTUREACCESS_STATIC, + resolution.first, resolution.second); + if (texture) { + // 2. Upload the raw pixel data + // Pitch is the number of bytes in a row (width * 4 bytes for RGBA) + SDL_UpdateTexture(texture, nullptr, rawData.data(), resolution.first * 4); + // 3. Set filtering (Scaling mode) + // SDL_SCALEMODE_LINEAR is the equivalent to GL_LINEAR + SDL_SetTextureScaleMode(texture, SDL_SCALEMODE_LINEAR); + + // 4. Store in your map + // In SDL3 + Dear ImGui, ImTextureID is typically just the SDL_Texture pointer + thumbnail_textures.insert_or_assign(filename, (ImTextureID)texture); + } + } + thumbnail_rawData.clear(); +} + +void MediaBrowserPopup::clean_thumbnail(){ + thumbnail_rawData.clear(); +} + +void MediaBrowserPopup::clean_textures(){ + for(auto& i : thumbnail_textures){ + ImTextureID textureID = i.second; + SDL_DestroyTexture((SDL_Texture*)textureID); + } + thumbnail_textures.clear(); } \ No newline at end of file diff --git a/src/master/popup/media_browser_popwin.h b/src/master/popup/media_browser_popwin.h index 6c17523c..c48df7b6 100644 --- a/src/master/popup/media_browser_popwin.h +++ b/src/master/popup/media_browser_popwin.h @@ -1,5 +1,7 @@ #pragma once #include "base_pop_window.h" +#include +#include class MediaBrowserPopup : public BasePopWindow { public: @@ -20,6 +22,13 @@ class MediaBrowserPopup : public BasePopWindow { virtual void open_dialog_for_download_file_selection(); virtual void download_all_folder_callback(const std::string folder); virtual void download_file_callback(const std::string fullpath); + + virtual void add_thumbnail(const std::string filename, const std::vector rawData, const std::pair resolution); + virtual void convert_rawData_to_texture(); + virtual void clean_thumbnail(); + virtual void clean_textures(); private: std::string selected = ""; + std::unordered_map, std::pair>> thumbnail_rawData; + std::unordered_map thumbnail_textures; }; \ No newline at end of file diff --git a/src/server/private/webcam.cpp b/src/server/private/webcam.cpp index d6b7fb33..cb8255d9 100644 --- a/src/server/private/webcam.cpp +++ b/src/server/private/webcam.cpp @@ -62,7 +62,6 @@ void GoProController::_webcamOff(std::string target){ _getSingleResponse(target, "/gopro/webcam/stop"); } - std::pair GoProController::_webcamStatus(std::string target){ return _getSingleResponse(target, "/gopro/webcam/status"); } From 31440efdc345b168c0548679b099d16c61395256 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Tue, 12 May 2026 11:30:10 +0800 Subject: [PATCH 63/64] Make master access the global state --- src/master/GoProMaster.cpp | 2 ++ src/master/main.cpp | 42 +++++++++++++++++++------------------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/master/GoProMaster.cpp b/src/master/GoProMaster.cpp index f1576115..509db87e 100644 --- a/src/master/GoProMaster.cpp +++ b/src/master/GoProMaster.cpp @@ -13,6 +13,8 @@ namespace fs = std::filesystem; +extern std::shared_ptr global_state; + GoProMaster::GoProMaster() { t1 = std::thread(&GoProMaster::update, this); std::cout << "GoProMaster created" << std::endl; diff --git a/src/master/main.cpp b/src/master/main.cpp index 70a2cb3c..4b04b4bf 100644 --- a/src/master/main.cpp +++ b/src/master/main.cpp @@ -26,27 +26,27 @@ c[d] = a; \ a = std::make_shared(r, gui, global_state, master); \ c[d] = a; \ -static std::queue command_queue = std::queue(); -static std::shared_ptr master = std::make_shared(); -static std::shared_ptr gui; -static std::shared_ptr servers; -static std::shared_ptr presets; -static std::shared_ptr global_state = std::make_shared(); - -static std::shared_ptr camera_list_win; -static std::shared_ptr inspector_win; -static std::shared_ptr websocket_win; -static std::shared_ptr style_setting_win; -static std::shared_ptr windows_array[4]; - -static std::shared_ptr add_camera_popwin; -static std::shared_ptr scan_camera_popwin; -static std::shared_ptr start_webcam_popwin; -static std::shared_ptr preview_popwin; -static std::shared_ptr add_preset_popwin; -static std::shared_ptr preset_manager_popwin; -static std::shared_ptr media_browser_popwin; -static std::shared_ptr pop_windows_array[7]; +std::queue command_queue = std::queue(); +std::shared_ptr master = std::make_shared(); +std::shared_ptr gui; +std::shared_ptr servers; +std::shared_ptr presets; +std::shared_ptr global_state = std::make_shared(); + +std::shared_ptr camera_list_win; +std::shared_ptr inspector_win; +std::shared_ptr websocket_win; +std::shared_ptr style_setting_win; +std::shared_ptr windows_array[4]; + +std::shared_ptr add_camera_popwin; +std::shared_ptr scan_camera_popwin; +std::shared_ptr start_webcam_popwin; +std::shared_ptr preview_popwin; +std::shared_ptr add_preset_popwin; +std::shared_ptr preset_manager_popwin; +std::shared_ptr media_browser_popwin; +std::shared_ptr pop_windows_array[7]; // All the window flags ExecutionType execution_type = ExecutionType::SetAll; From d48add702dbdce4e16c171eeacdb320152905863 Mon Sep 17 00:00:00 2001 From: ZhuElly <34325707+Elly2018@users.noreply.github.com> Date: Tue, 12 May 2026 11:36:10 +0800 Subject: [PATCH 64/64] Update version for package config files --- package/deb_master_amd64 | 2 +- package/deb_server_amd64 | 2 +- package/deb_server_arm64 | 2 +- package/win_master_x64.iss | 2 +- package/win_server_x64.iss | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package/deb_master_amd64 b/package/deb_master_amd64 index 2d4b0a1d..a5cab6c4 100644 --- a/package/deb_master_amd64 +++ b/package/deb_master_amd64 @@ -1,5 +1,5 @@ Package: go-pro-control-master -Version: 1.0.5 +Version: 1.0.6 Section: shells Priority: optional Architecture: amd64 diff --git a/package/deb_server_amd64 b/package/deb_server_amd64 index 1b9e4306..06aa0d35 100644 --- a/package/deb_server_amd64 +++ b/package/deb_server_amd64 @@ -1,5 +1,5 @@ Package: go-pro-control-server -Version: 1.0.5 +Version: 1.0.6 Section: shells Priority: optional Architecture: amd64 diff --git a/package/deb_server_arm64 b/package/deb_server_arm64 index efad9912..016efb48 100644 --- a/package/deb_server_arm64 +++ b/package/deb_server_arm64 @@ -1,5 +1,5 @@ Package: go-pro-control-server -Version: 1.0.5 +Version: 1.0.6 Section: shells Priority: optional Architecture: arm64 diff --git a/package/win_master_x64.iss b/package/win_master_x64.iss index 3a1f1ee0..5028bc0c 100755 --- a/package/win_master_x64.iss +++ b/package/win_master_x64.iss @@ -3,7 +3,7 @@ ; Non-commercial use only #define MyAppName "GoPro Master" -#define MyAppVersion "1.0.5" +#define MyAppVersion "1.0.6" #define MyAppPublisher "Elly" #define MyAppURL "https://github.com/Elly2018/GoPro_Controller" #define MyAppExeName "go-pro-master.exe" diff --git a/package/win_server_x64.iss b/package/win_server_x64.iss index 4853d8c9..4424e059 100755 --- a/package/win_server_x64.iss +++ b/package/win_server_x64.iss @@ -3,7 +3,7 @@ ; Non-commercial use only #define MyAppName "GoPro Server" -#define MyAppVersion "1.0.5" +#define MyAppVersion "1.0.6" #define MyAppPublisher "Elly" #define MyAppURL "https://github.com/Elly2018/GoPro_Controller" #define MyAppExeName "go-pro-server.exe"